先解釋兩個概念。
- 等待池:假設一個線程A調用了某個對象的wait()方法,線程A就會釋放該對象的鎖后,進入到了該對象的等待池,等待池中的線程不會去競爭該對象的鎖。
- 鎖池:只有獲取了對象的鎖,線程才能執行對象的 synchronized 代碼,對象的鎖每次只有一個線程可以獲得,其他線程只能在鎖池中等待
區別:
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
- Java 自學指南
- Java 面試題匯總PC端瀏覽【點這里】
- Java知識圖譜
- Java 面試題匯總小程序瀏覽,掃二維碼
所有資源資源匯總於公眾號