理解高併發(9).線程通信之_wait、notify

消息通信的兩種模型:
  • 消息傳遞
wait/notify是採用該種機制實現的。 是藉助於操作系統底層的消息通信機制。
  • 共享內存
多線程中的數據同步的內存可見性是基於些模型。例如,A線程修改了變量值,
該變量的值會先寫回主內存,然後再由B線程從主內存讀取過來。

概念
wait: 當前線程釋放鎖的使用權,進入阻塞階段
notify: 隨機喚醒一個阻塞的線程,讓它從新獲取鎖的使用權
notifyall: 喚醒對象頭中wait隊列的所有線程,所有線程竟爭上崗搶佔鎖控制權

用途&場景
操作共享資源時,一線程阻塞掛起,真到另一線程通知喚醒才繼續執行。
適用於生產者-消費者模型。

原理
Q:wait和notify爲什麼一定要放在synchronized裏面?
A: 從2個層面理解:
第1個層面: 現實中的例子說起, 你坐公交車讓位置, 你首先得獲取到位置(資源)纔行,而獲取到位置的途徑只能是通過搶佔(synchronized), 所以說,wait和notify需要在synchronized塊之中;
第2個層面: 實現原理, 線程是基於對象的,在對象頭裏面會有一個wait隊列、owner和計數器, 如果要釋放鎖和喚醒線程,首先需要獲取到對象,只有獲取到對象才能操作對象頭裏面的monitor,而獲取對象的唯一方法就是synchronized。

代碼例子
以下例子如果take線程不執行notify,那麼put線程將一直停留在那兒。
final Account account = new Account();
Thread put = new Thread(new Runnable(){
public void run(){
synchronized(account){
try {
System.out.println("put will wait");
account.wait();
System.out.println("put over");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread take = new Thread(new Runnable(){
public void run(){
synchronized(account){
System.out.println("take will notify");
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("take notify over");
//account.notify();
}
}
});

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章