java 线程之间通信以及notify与notifyAll区别。
jvm多个线程间的通信是通过 线程的锁、条件语句、以及wait()、notify()/notifyAll组成。
下面来实现一个启用多个线程来循环的输出两个不同的语句。
package com.app.thread;
import javax.swing.plaf.SliderUI;
/**
* 看出问题来
* @author Gordon
*
*/
public class LockDemo {
public static void main(String[] args) {
// System.out.println("lock");
final OutTurn ot = new OutTurn();
for(int j=0;j<100;j++){
new Thread(new Runnable() {
public void run() {
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
for (int i = 0; i <5; i++) {
ot.sub();
}
}
}).start();
new Thread(new Runnable() {
public void run() {
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
for (int i = 0; i < 5; i++) {
ot.main();
}
}
}).start();
}
}
}
class OutTurn {
private boolean isSub = true;
private int count=0;
public synchronized void sub() {
try {
while (!isSub) {
this.wait();
}
System.out.println("sub ---- "+count);
isSub=false;
this.notify();
} catch (Exception e) {
e.printStackTrace();
}
count++;
}
public synchronized void main() {
try {
while(isSub){
this.wait();
}
System.out.println("main (((((((((((( "+count);
isSub=true;
this.notify();
} catch (Exception e) {
e.printStackTrace();
}
count++;
}
}
不知能否看出问题,第一次写的时候出现了问题,找了很久才找了出来,一直以来是没有注意notify与notifyAll()的使用,在此酿成大错,哎。。。
说明一下notify与notifyAll的区别:
以上sub和main方法都是用了锁,所以说多个调用sub方法的线程和多个调用main方法的都会处于阻塞状态,都会等待一个正在运行的其他线程来唤醒他们,以上代码使用了notify进行唤醒,notify只能唤醒一个线程,其他等待的线程仍然处于wait状态,如果调用sub方法的线程执行完后,所有的线程都处于等待状态,isSub=false了,这时唤醒的是一个sub方法调度线程,那么while循环等于true,则该线程也会处于等待状态,之后所有的线程处于等待状态,没有运行的线程来唤醒他们,这时就产生了死锁。如果使用notifyAll()来唤醒所有正在等待该锁的线程,那么所有的线程都会处于运行前的准备状态,就是sub方法执行完后,唤醒了所有等待该锁的状态,那么即使再次唤醒一个sub方法调度线程,那么该线程再次处于等待状态后,还有其他的线程可以获得该锁,进入运行状态。所以notify方法很容易引起死锁,除非你根据自己的程序设计,确定不会引起死锁,notifyAll则是线程的安全唤醒方法。
言归正传,以上代码 只需要将sub和main方法中的参数改成this.notifyAll()即可。