JAVA 多线程实现(五)

2014-11-24 03:24:28 · 作者: · 浏览: 3
捉,可以做一些事情。

如果你实在搞不清楚notify和notifyAll的区别,那么你就使用notifyAll,尽管这样
会带来效率上的牺牲,但是,notifyAll是安全的。

线程的运用会产生missed notification,即,某个线程B较早地进入了通知的方法
而另外一个线程A在睡眠中,没有等到通知,等B通知完了,才进入wait状态。
解决漏掉的通知的方法就是加入一个开关,
当某个线程已经发出通知了,这么这个开关就关闭,另外一个调用线程wait之前需要判断
一下这个开关,如果开关关闭了,就不能wait,直接下一步业务逻辑。

和漏掉通知相比,通知过早(early notification)也是一个问题,这个问题最常见的发生场景
是有三个线程 线程A 线程B 和线程C
线程A 和 B负责删除一个List容器的元素,线程C负责增加一个元素
线程A和线程B在删除之前要先判断是否List为空,如果为空,就等待,否则就执行删除
线程C在增加一个元素之后发出通知,通知A和B可以删除了

问题就出在,你不知道A和B哪个线程会先执行,当A执行的时候,A把C增加的元素删除了
然后A让出对象锁,这个时候B抢到对象锁,开始执行,可是B抢到对象锁之后List的元素已经
被删除了,这样B的删除操作就会抛出异常。相对于B来说,C的通知就显得过早了,这就是
所谓的early notification

synchronized(List){
C.addElement();
}

synchronized(List){
if(List.size() == 0){
A or B wait();
}
A or B removeElement();
}

其实,如果将if换成while那么这个问题就将被杜绝。

等待一个线程死亡的方法join()
使用这个方法,当前线程会立即被则色,直到等待调用join()方法的线程死亡之后执行。

package cn.bj.brook.test;

public class MainRun {

int i = 0;

public static void main(String[] args) {
MainRun mr = new MainRun();
T1 t1 = new T1(mr);
T2 t2 = new T2(mr);
Thread th1 = new Thread(t1,"ThreadA");
Thread th2 = new Thread(t2,"ThreadB");
th1.start();
try {
th1.join();
} catch (InterruptedException e) {
}
th2.start();
}

}


class T1 implements Runnable{

MainRun mr = null;
T1(MainRun mr){
this.mr = mr;
}
@Override
public void run() {
while(true){
try {
System.out.println("In Thread T1 Running");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

class T2 implements Runnable{
MainRun mr = null;
T2(MainRun mr){
this.mr = mr;
}
@Override
public void run() {
while(true){
try {
System.out.println("In Thread T2 Running");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

像上面这段代码 th2将永远得不到执行的机会,因为在main里,主线程会一直被th1线程阻塞,th1线程不死掉
th2就不会运行。
join方法可以设置一个超时值作为参数,当等待的时间过了这个超时值之后,线程就会自动执行。

摘自 zmyxmjz的专栏