notify() 和 notifyAll() 有什么区别?
综上,所谓唤醒线程,另一种解释可以说是将线程由等待池移动到锁池,notifyAll调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify只会唤醒一个线程。
有了这些理论基础,后面的notify可能会导致死锁,而notifyAll则不会的例子也就好解释了
public class TestNotifyNotifyAll { private static Object obj = new Object(); public static void main(String[] args) { //测试 RunnableImplA wait() Thread t1 = new Thread(new RunnableImplA(obj)); Thread t2 = new Thread(new RunnableImplA(obj)); t1.start(); t2.start(); //RunnableImplB notify() Thread t3 = new Thread(new RunnableImplB(obj)); t3.start(); // //RunnableImplC notifyAll() // Thread t4 = new Thread(new RunnableImplC(obj)); // t4.start(); } } class RunnableImplA implements Runnable { private Object obj; public RunnableImplA(Object obj) { this.obj = obj; } public void run() { System.out.println("run on RunnableImplA"); synchronized (obj) { System.out.println("obj to wait on RunnableImplA"); try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("obj continue to run on RunnableImplA"); } } } class RunnableImplB implements Runnable { private Object obj; public RunnableImplB(Object obj) { this.obj = obj; } public void run() { System.out.println("run on RunnableImplB"); System.out.println("睡眠3秒..."); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj) { System.out.println("notify obj on RunnableImplB"); obj.notify(); } } } class RunnableImplC implements Runnable { private Object obj; public RunnableImplC(Object obj) { this.obj = obj; } public void run() { System.out.println("run on RunnableImplC"); System.out.println("睡眠3秒..."); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj) { System.out.println("notifyAll obj on RunnableImplC"); obj.notifyAll(); } } }
结果:仅调用一次 obj.notify(),线程 t1 或 t2 中的一个始终在等待被唤醒,程序不终止
run on RunnableImplA
obj to wait on RunnableImplA
run on RunnableImplA
obj to wait on RunnableImplA
run on RunnableImplB
睡眠3秒...
notify obj on RunnableImplB
obj continue to run on RunnableImplA
把 t3 注掉,启动 t4 线程。调用 obj.notifyAll() 方法
public class TestNotifyNotifyAll { private static Object obj = new Object(); public static void main(String[] args) { //测试 RunnableImplA wait() Thread t1 = new Thread(new RunnableImplA(obj)); Thread t2 = new Thread(new RunnableImplA(obj)); t1.start(); t2.start(); // //RunnableImplB notify() // Thread t3 = new Thread(new RunnableImplB(obj)); // t3.start(); //RunnableImplC notifyAll() Thread t4 = new Thread(new RunnableImplC(obj)); t4.start(); } }
结果:t1、t2线程均可以执行完毕
run on RunnableImplA
obj to wait on RunnableImplA
run on RunnableImplA
obj to wait on RunnableImplA
run on RunnableImplC
睡眠3秒...
notifyAll obj on RunnableImplC
obj continue to run on RunnableImplA
obj continue to run on RunnableImplA