等待喚醒(wait / notify)機制
如果一個執行緒從頭到尾執行完也不和別的執行緒打交道的話,那就不會有各種安全性問題了。但是協作越來越成為社會發展的大勢,一個大任務拆成若干個小任務之後,各個小任務之間可能也需要相互協作最終才能執行完整個大任務。所以各個執行緒在執行過程中可以相互通訊
,所謂通訊
就是指相互交換一些資料或者傳送一些控制指令,比如一個執行緒給另一個暫停執行的執行緒傳送一個恢復執行的指令,下邊詳細看都有哪些通訊方式。
volatile和synchronized
可變共享變數是天然的通訊媒介,也就是說一個執行緒如果想和另一個執行緒通訊的話,可以修改某個在多執行緒間共享的變數,另一個執行緒通過讀取這個共享變數來獲取通訊的內容。
由於原子性操作、記憶體可見性和指令重排序的存在,java提供了volatile
和synchronized
的同步手段來保證通訊內容的正確性,假如沒有這些同步手段,一個執行緒的寫入不能被另一個執行緒立即觀測到,那這種通訊就是不靠譜的~
wait/notify機制
故事背景
也不知道是那個遭天殺的給我們學校廁所的坑裡塞了個塑料瓶,導致樓道里如黃河氾濫一般,臭味熏天。更加悲催的是整個樓只有這麼一個廁所,比這個更悲催的是這個廁所裡只有一個坑!!!!!好吧,讓我們用java來描述一下這個廁所:
public class Washroom { private volatile boolean isAvailable = false; //表示廁所是否是可用的狀態 private Object lock = new Object(); //廁所門的鎖 public boolean isAvailable() { return isAvailable; } public void setAvailable(boolean available) { this.isAvailable = available; } public Object getLock() { return lock; } }
isAvailable
欄位代表廁所是否可用,由於廁所損壞,預設是false
的,lock
欄位代表這個廁所門的鎖。需要注意的是isAvailable
欄位被volatile
修飾,也就是說有一個執行緒修改了它的值,它可以立即對別的執行緒可見~
由於廁所資源寶貴,英明的學校領導立即擬定了一個修復任務:
public class RepairTask implements Runnable { private Washroom washroom; public RepairTask(Washroom washroom) { this.washroom = washroom; } @Override public void run() { synchronized (washroom.getLock()) { System.out.println("維修工 獲取了廁所的鎖"); System.out.println("廁所維修中,維修廁所是一件辛苦活,需要很長時間。。。"); try { Thread.sleep(5000L); //用執行緒sleep表示維修的過程 } catch (InterruptedException e) { throw new RuntimeException(e); } washroom.setAvailable(true); //維修結束把廁所置為可用狀態 System.out.println("維修工把廁所修好了,準備釋放鎖了"); } } }
這個維修計劃的內容就是當維修工進入廁所之後,先把門鎖上,然後開始維修,維修結束之後把Washroom
的isAvailable
欄位設定為true
,以表示廁所可用。
與此同時,一群急得像熱鍋上的螞蟻的傢伙在廁所門前打轉轉,他們想做神馬不用我明說了吧