今天看到开源中国上有这样一个问答:假设我有两个对象锁,对象A锁有5个线程在等待,对象B锁有3个线程在等待,对象A锁中的线程执行完,这时调用notifyAll,是唤醒了对象AB两个锁的全部的等待线程还是只唤醒了A锁的5个线程?
1. 方法文档解释
通过看该方法文档的解释,可以得出下面结论:
- notifyAll()中All的含义是所有的线程,而不是所有的锁,只能唤醒等待(调用wait()方法等待)同一个锁的所有线程。notifyAll()执行后,只有一个线程能得到锁,其他没有得到锁的线程会继续保持在等待状态。【notifyAll()只能释放一把锁。】
- notifyAll()必须在当前线程拥有监视器锁的情况下执行,否则将抛出异常IllegalMonitorStateException。
2. 代码解释
定义两个对象锁,每个对象分别有两个进程,先将对象一里线程A与线程B启动,进入等待状态;在把对象二里的线程C启动,也进入等待状态;接着将对象二里的线程D启动并唤醒其他线程。
1package person.xsc.practice; 2 3public class ThreadWaitAndNotifyAll implements Runnable{ 4 private static Object object1 = new Object(); 5 private static Object object2 = new Object(); 6 @Override 7 public void run() { 8 synchronized (object1) { 9 System.out.println(Thread.currentThread().getName() + "获得锁,进入等待状态"); 10 try { 11 object1.wait(); 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } 15 System.out.println(Thread.currentThread().getName() + "执行最后部分结束"); 16 } 17 } 18 public static void main(String[] args) { 19 ThreadWaitAndNotifyAll runnable = new ThreadWaitAndNotifyAll(); 20 Thread threadA = new Thread(runnable,"线程A"); 21 Thread threadB = new Thread(runnable,"线程B"); 22 Thread threadC=new Thread(new Runnable() { 23 @Override 24 public void run() { 25 // TODO Auto-generated method stub 26 synchronized (object2) { 27 System.out.println(Thread.currentThread().getName() + "获得锁,进入等待状态"); 28 try { 29 object2.wait(); 30 } catch (InterruptedException e) { 31 e.printStackTrace(); 32 } 33 System.out.println(Thread.currentThread().getName() + "执行结束"); 34 } 35 } 36 37 },"线程D"); 38 Thread threadD = new Thread(new Runnable() { 39 @Override 40 public void run() { 41 synchronized (object2) { 42 System.out.println(Thread.currentThread().getName() + "获得锁,开始通知唤醒所有线程"); 43 // 唤醒其他线程 44 object2.notifyAll(); 45 // 调用完notifyAll()方法后,同步代码块中的其他代码,必须执行完后才能将对象锁释放,而不是调用了notifyAll()方法后立即释放。 46 System.out.println(Thread.currentThread().getName() + "执行结束"); 47 } 48 } 49 },"线程C"); 50 // 每次运行,线程0和线程1的顺序可能会不同,执行顺序由CPU决定 51 threadA.start(); 52 threadB.start(); 53 try { 54 Thread.sleep(100); 55 } catch (InterruptedException e) { 56 e.printStackTrace(); 57 } 58 threadC.start(); 59 threadD.start(); 60 } 61 } 62输出: 63线程A获得锁,进入等待状态 64线程B获得锁,进入等待状态 65线程D获得锁,进入等待状态 66线程C获得锁,开始通知唤醒所有线程 67线程C执行结束 68线程D执行结束 69
根据上面代码运行结果来看,确实如方法文档所说的那样:notifyAll()只能唤醒等待同一个锁的所有线程。
