首页 > 技术文章 > java 线程之间通信以及notify与notifyAll区别。

chengpeng15 2016-08-28 00:34 原文

 

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()即可。

推荐阅读