wait()、notify()、notifyAll()是三個定義在Object類裏的方法,用來控制線程的狀態,通常與synchronized合用。這三個方法最終調用的都是jvm的native方法, 隨着jvm運行平臺的不一樣可能有些許差別。java
當線程執行wait()方法時候,會釋放當前對象的控制權,而後讓出CPU,進入等待狀態;
只有當 notify/notifyAll() 被執行時候,纔會喚醒一個或多個正處於等待狀態的線程(並不會馬上釋放控制權),而後繼續往下執行,直到執行完synchronized 代碼塊的代碼或是中途遇到wait() ,再次釋放鎖。多線程
wait() 須要被try catch包圍,拋出InterruptedException; 中斷也可使wait等待的線程喚醒。
notify方法只喚醒一個等待對象的線程並使該線程開始執行。因此若是有多個線程等待一個對象,這個方法只會喚醒其中一個線程,選擇哪一個線程取決於操做系統對多線程管理的實現。
notifyAll 會喚醒全部等待對象的線程,哪個線程將會第一個處理取決於操做系統的實現。jvm
要注意的是:spa
eg.1操作系統
import lombok.extern.slf4j.Slf4j; @Slf4j public class SyncTest { public static void main(String[] args) { Object obj = new Object(); Thread thread1 = new Thread(() -> { synchronized (obj) { try { log.info("1-before wait"); obj.wait(); log.info("1-after wait"); } catch (Exception e) { e.printStackTrace(); } } }); Thread thread2 = new Thread(() -> { synchronized (obj) { try { log.info("2-before wait"); obj.wait(); log.info("2-after wait"); } catch (Exception e) { e.printStackTrace(); } } }); Thread thread3 = new Thread(() -> { synchronized (obj) { try { log.info("3-before notifyAll"); obj.notifyAll(); try { Thread.currentThread().sleep(2000); } catch (Exception e) { e.printStackTrace(); } log.info("3-after notifyAll"); } catch (Exception e) { e.printStackTrace(); } } try { Thread.currentThread().sleep(2000); } catch (Exception e) { e.printStackTrace(); } log.info("3-out synchronized"); }); thread1.start(); thread2.start(); try { Thread.currentThread().sleep(2000); } catch (InterruptedException e1) { e1.printStackTrace(); } thread3.start(); } }
結果: 線程3在sleep前,已經notifyall。但在sleep的時間中,線程1和線程2並無繼續執行。.net
2018-10-23 16:15:22,897 [Thread-1] INFO [SyncTest] [SyncTest.java:24] 2-before wait 2018-10-23 16:15:22,906 [Thread-0] INFO [SyncTest] [SyncTest.java:11] 1-before wait 2018-10-23 16:15:23,896 [Thread-2] INFO [SyncTest] [SyncTest.java:43] 3-before notifyAll 2018-10-23 16:15:25,896 [Thread-2] INFO [SyncTest] [SyncTest.java:50] 3-after notifyAll 2018-10-23 16:15:25,898 [Thread-0] INFO [SyncTest] [SyncTest.java:13] 1-after wait 2018-10-23 16:15:25,898 [Thread-1] INFO [SyncTest] [SyncTest.java:26] 2-after wait 2018-10-23 16:15:27,897 [Thread-2] INFO [SyncTest] [SyncTest.java:61] 3-out synchronized
驗證:擁有控制權的線程notify在結束執行synchronized塊以前時,控制權不會釋放!線程
eg.2code
import lombok.extern.slf4j.Slf4j; @Slf4j public class SyncTest { public static void main(String[] args) { Object obj = new Object(); Thread thread1 = new Thread(() -> { synchronized (obj) { try { log.info("1-before wait"); obj.wait(); log.info("1-after wait"); } catch (Exception e) { log.info("1-catch {}. interrupt狀態: {}", e.toString(), Thread.currentThread().isInterrupted()); Thread.currentThread().interrupt(); log.info("設置標誌位後interrupt狀態: {}", Thread.currentThread().isInterrupted()); } } }); thread1.start(); try { Thread.currentThread().sleep(2000); } catch (InterruptedException e1) { e1.printStackTrace(); } log.info("線程初始interrupt狀態:{}", thread1.isInterrupted()); thread1.interrupt(); } }
結果: 當線程調用interrupt()時,wait()拋出的InterruptedException被線程捕獲。對象
2018-10-23 17:13:38,047 [Thread-0] INFO [SyncTest] [SyncTest.java:10] 1-before wait 2018-10-23 17:13:40,042 [main] INFO [SyncTest] [SyncTest.java:28] 線程初始interrupt狀態:false 2018-10-23 17:13:40,044 [Thread-0] INFO [SyncTest] [SyncTest.java:14] 1-catch java.lang.InterruptedException. interrupt狀態: false 2018-10-23 17:13:40,044 [Thread-0] INFO [SyncTest] [SyncTest.java:16] 設置標誌位後interrupt狀態: true
驗證:Thread.currentThread().interrupt() 與 thread1.interrupt() 做用類似, 將中斷標記位設置爲true。 拋出的異常被捕獲後,中斷標示會被清除!blog