第13章多线程第三讲
来源:互联网 发布:nginx api for lua 编辑:程序博客网 时间:2024/04/30 13:52
互斥锁
µ 每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
µ Java对象默认是可以被多个线程共用的,只是在需要时才启动“互斥锁”机制,成为专用对象。
µ 关键字synchronized用来与对象的互斥锁联系
µ 当某个对象用synchronized修饰时,表明该对象已启动“互斥锁”机制,在任一时刻只能由一个线程访问,即使该线程出现堵塞,该对象的被锁定状态也不会解除,其他线程任不能访问该对象。
µ synchronized关键字的使用方式有两种:
¯ 用在对象前面限制一段代码的执行(同步代码块)
public void push(char c){
…
sychronized(this){
data[index]=c;
index++
}
}
¯ 用在方法声明中,表示整个方法为同步方法
µ 同步好处:决了线程安全问题
µ 同步弊端
ü 降低了运行效率(判断锁是较为消耗资源的)
ü 同步嵌套,容易出现死锁
死锁
两个线程A、B用到同一个对象s(s为共享资源),且线程A在执行中要用到B运行后所创造的条件。在这种前提下A先开始运行,进入同步块后,对象s被锁定,接着线程A因等待B运行结束而进入阻塞状态,于是B开始运行,但因无法访问对象s,线程B也进入阻塞状态,等待s被线程A解锁。最终的结果:两个线程互相等待,都无法运行。
线程死锁举例TestDeadLock2.java
分析:这是线程死锁的典型表现,两个以上线程并发运行,他们均因其他线程锁定了自己运行所需资源而陷入阻塞状态,同时自己也锁定了其他线程所需资源。
public class TestDeadLock2 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
char[] a={'a','b','c'};
char[] b={'d','e','f'};
MyThread1 t1=new MyThread1(a,b);
MyThread1 t2=new MyThread1(b,a);
t1.start();
t2.start();
}
}
class MyThread1 extends Thread{
private char[] source;
private char[] dest;
public MyThread1(char[] source,char[] dest){
this.source=source;
this.dest=dest;
}
public void run(){
synchronized(source){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(dest){
System.arraycopy(source,0,dest,0,source.length);;
System.out.println(dest);
}
}
}
}
¯ 线程同步通信
为避免死锁,就应该让线程在进入阻塞状态时尽量释放其锁定的资源,以为其他的线程提供运行的机会,Object类中定义了几个有用的方法:wait()、notify()、notifyAll()。
µ wait():被锁定的对象可以调用wait()方法,这将导致当前线程被阻塞并释放该对象的互斥锁,即解除了wait()方法当前对象的锁定状态,其他的线程就有机会访问该对象。
µ notify():唤醒调用wait()方法后被阻塞的线程。每次运行该方法只能唤醒一个线程。
µ notifyAll():唤醒所有调用wait()方法被阻塞的线程。
¯ java.util包中的Timer和TimerTask类也可实现多线程
¯ Timer类实现的是类似闹钟的功能,也就是定时或者每隔一定时间间隔触发一次线程。
¯ TimerTask类是一个抽象类,该类实现了Runnable接口,具备多线程的能力。
¯ 通过继承TimerTask类创建子类,使该子类获得多线程的能力,将需要多线程执行的代码书写在run方法内部,然后通过Timer类启动线程的执行。
¯ schedule()方法
µ public void schedule(TimerTask task,Date time):该方法的作用是在到达time指定的时间或已经超过该时间时执行线程task。
Date d = new Date(2009-1900,10-1,1,10,0,0);
t. schedule(task,d);
µ public void schedule(TimerTask task, Date firstTime, long period):在时间到达firstTime开始,每隔period毫秒就启动一次task指定的线程,这种方式会重复启动线程。
Date d = new Date(2009-1900,10-1,1,10,0,0);
t. schedule(task,d,20000);
µ public void schedule(TimerTask task,long delay)在执行schedule方法delay毫秒以后启动线程task。
t.schedule(task,1000);//在执行该行启动代码1000毫秒后启动一次线程task
µ public void schedule(TimerTask task,long delay,long period):在执行schedule方法delay毫秒以后启动线程task,然后每隔period毫秒重复启动线程task。
总结:
本节要注意互斥锁和同步的优势和弊端
µ 每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
µ Java对象默认是可以被多个线程共用的,只是在需要时才启动“互斥锁”机制,成为专用对象。
µ 关键字synchronized用来与对象的互斥锁联系
µ 当某个对象用synchronized修饰时,表明该对象已启动“互斥锁”机制,在任一时刻只能由一个线程访问,即使该线程出现堵塞,该对象的被锁定状态也不会解除,其他线程任不能访问该对象。
µ synchronized关键字的使用方式有两种:
¯ 用在对象前面限制一段代码的执行(同步代码块)
public void push(char c){
…
sychronized(this){
data[index]=c;
index++
}
}
¯ 用在方法声明中,表示整个方法为同步方法
µ 同步好处:决了线程安全问题
µ 同步弊端
ü 降低了运行效率(判断锁是较为消耗资源的)
ü 同步嵌套,容易出现死锁
- 第13章多线程第三讲
- 第十三章 多线程 第三讲
- 第十三章 多线程 第三讲
- 第8讲多线程
- 第15讲 c++多线程
- (第三阶段)第31讲
- 第三讲
- 第三讲
- 第十三章 多线程 第一讲
- 第十三章 多线程 第二讲
- 第十三章 多线程 第一讲
- 第十三章 多线程 第二讲
- 第三章 多线程
- 多线程第三章(1)
- 第13讲 画笔示例
- 第13讲 Uboot移植
- 16位汇编第七讲汇编指令详解第第三讲
- 第三章 ---- 第三节
- 数据类型
- 快速排序
- C++ 错误列表
- 各巨头竞相争夺海量数据云分析市场
- PHP Smarty 用法
- 第13章多线程第三讲
- java流与文件操作
- Java流与文件操作(3)
- 磁盘即将过时 闪存为王
- javascript小技巧
- 程序员怎样提高效率
- 简单工厂(Factory)模式
- Java流与文件操作(4)
- Linux添加/删除用户和用户组