等待喚醒機制
線程的狀態
- NEW 至今尚未啟動的線程處於這種狀態
- RUNNABLE 正在Java虛擬機中執行的線程處於這種狀態
- BLOCKED 受阻塞並等待某個監視器鎖的線程處於這種狀態
- WAITING 無限期的等待另一個線程來執行某一待定操作的線程處於這種狀態
- TIMED_WAITNG 等待另一個線程來執行取決於指定等待時間的操作的線程處於這種狀態
- TERMINATED 已退出的線程處於這種狀態。
- 阻塞狀態:具有cpu的執行資格,等待cpu空閑時執行
- 休眠狀態:放棄cpu的執行資格,cpu空閑,也不執行
等待喚醒案例分析
public static void sleep(Long millis):使用當前正在執行的線程以指定的毫秒數暫停(暫停停止執行).
- 毫秒數結束之后,線程繼續執行
等待喚醒案例:線程之間的通信
- 創建一個顧客線程(消費者):告知老板要包子的中類和數量,調用wait方法,放棄cpu的執行,進入到WAITNG狀態(無限等待)
- 創建一個老板線程(生產者):花了5秒做包子,做好包子之后,調用notify方法,喚醒顧客吃包子
注意:
- 顧客和老板線程必須使用同步代碼塊包裹起來,保證等待和喚醒只能有一個在執行
- 同步使用的鎖對象必須保證唯一
- 只有鎖對象才能調用wait和notify方法
Object類中的方法
void wait()
- 在其他線程調用此對象的notify()方法或notify() 方法前,導致當前線程等待。
void notify()
- 喚醒在此對象監視器上等待的單個線程。
- 會繼續執行wait方法之后的代碼
public class CaiNiao{
public static void main(String[] args){ //創建鎖對象,保證唯一 Object obj = new Object(); //創建一個顧客線程(消費者) new Thread(){ @Override public void run(){ //一直等着買包子 while(true){ //保證等待和喚醒的線程只能有一個執行,需要使用同步技術 syncharonized (obj){ System.out.println("告知老板要的包子的種類和數量"); //調用wait方法,放棄cpu的執行,進入到WAITNG狀態(無限等待) try{ obj.wait(); }catch (InterruptedException e){ e.printStackTrace(); } //喚醒之后執行的代碼 System.out.println("包子已經做好了,開吃!"); System.out.println("--------------"); } } } }.start(); //創建一個老板線程(生產者) new Thread(){ @Override public void run(){ //一直做包子 while(true){ //花5秒做包子 try{ Thread.sleep(5000);//花5秒做包子 }catch(InterruptedException e); e.printStackTrace(); } //保證等待和喚醒只能有一個在執行,需要使用同步技術 syncharonized (obj){ System.out.println("花了5秒做包子,做好包子之后,調用notify方法,喚醒顧客吃包子"); //做好包子之后,調用notify方法,喚醒顧客吃包子 obj.notify(); } } }.start(); }
Object類中wait帶參方法和notify
進入到TimeWaiting(計時等待)有兩種方法
- 使用sleep(Long m)方法,在毫秒值結束之后,線程睡醒進入到Runnable/Blacked狀態
- 使用wait(Long m))方法,wait方法如果在毫秒值結束之后,還沒有被notify喚醒,就會自動醒來,線程睡醒進入到Runnable/Blacked狀態
喚醒的方法:
- void notify()喚醒在此對象監視器上等待的單個線程。
- void notifyAll()喚醒在此對象監視器上等待的所有線程。
調用wait和notify方法需要注意的細節
- wait方法與notify方法必須要由同一個鎖對象調用。因為:對應的鎖對象可以通過notify喚醒使用同一個鎖對象調用的wait方法后的線程
- wait方法與notify方法是屬於Object類的方法的。因為:鎖對象可以是任意對象,而任意對象的所屬類都是繼承了Object類的。
- wait方法與notify方法必須要在同步代碼塊或者是同步函數中使用。因為:必須要通過鎖對象調用這兩個方法。