notify() 和 notifyAll() 有什么區(qū)別?
先解釋兩個概念。
- 等待池:假設(shè)一個線程A調(diào)用了某個對象的wait()方法,線程A就會釋放該對象的鎖后,進入到了該對象的等待池,等待池中的線程不會去競爭該對象的鎖。
- 鎖池:只有獲取了對象的鎖,線程才能執(zhí)行對象的 synchronized 代碼,對象的鎖每次只有一個線程可以獲得,其他線程只能在鎖池中等待
然后再來說notify和notifyAll的區(qū)別
- 如果線程調(diào)用了對象的 wait()方法,那么線程便會處于該對象的等待池中,等待池中的線程不會去競爭該對象的鎖。
- 當(dāng)有線程調(diào)用了對象的 notifyAll()方法(喚醒所有 wait 線程)或 notify()方法(只隨機喚醒一個 wait 線程),被喚醒的的線程便會進入該對象的鎖池中,鎖池中的線程會去競爭該對象鎖。也就是說,調(diào)用了notify后只要一個線程會由等待池進入鎖池,而notifyAll會將該對象等待池內(nèi)的所有線程移動到鎖池中,等待鎖競爭
- 優(yōu)先級高的線程競爭到對象鎖的概率大,假若某線程沒有競爭到該對象鎖,它還會留在鎖池中,唯有線程再次調(diào)用 wait()方法,它才會重新回到等待池中。而競爭到對象鎖的線程則繼續(xù)往下執(zhí)行,直到執(zhí)行完了 synchronized 代碼塊,它會釋放掉該對象鎖,這時鎖池中的線程會繼續(xù)競爭該對象鎖。
綜上,所謂喚醒線程,另一種解釋可以說是將線程由等待池移動到鎖池,notifyAll調(diào)用后,會將全部線程由等待池移到鎖池,然后參與鎖的競爭,競爭成功則繼續(xù)執(zhí)行,如果不成功則留在鎖池等待鎖被釋放后再次參與競爭。而notify只會喚醒一個線程。文章源自四五設(shè)計網(wǎng)-http://www.wasochina.com/39801.html
有了這些理論基礎(chǔ),后面的notify可能會導(dǎo)致死鎖,而notifyAll則不會的例子也就好解釋了文章源自四五設(shè)計網(wǎng)-http://www.wasochina.com/39801.html
測試代碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | 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(); ?? } ? } } |
結(jié)果:僅調(diào)用一次 obj.notify(),線程 t1 或 t2 中的一個始終在等待被喚醒,程序不終止文章源自四五設(shè)計網(wǎng)-http://www.wasochina.com/39801.html
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文章源自四五設(shè)計網(wǎng)-http://www.wasochina.com/39801.html
把 t3 注掉,啟動 t4 線程。調(diào)用 obj.notifyAll() 方法文章源自四五設(shè)計網(wǎng)-http://www.wasochina.com/39801.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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(); ? } } |
結(jié)果:t1、t2線程均可以執(zhí)行完畢文章源自四五設(shè)計網(wǎng)-http://www.wasochina.com/39801.html
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文章源自四五設(shè)計網(wǎng)-http://www.wasochina.com/39801.html
到此這篇關(guān)于Java中notify()和notifyAll()的使用區(qū)別的文章就介紹到這了文章源自四五設(shè)計網(wǎng)-http://www.wasochina.com/39801.html 文章源自四五設(shè)計網(wǎng)-http://www.wasochina.com/39801.html


評論