《Java高併發編程詳解-多線程架構與設計》線程間的通信

摘自《Java高併發編程詳解-多線程架構與設計》第五章

同步、異步、阻塞、非阻塞概念

同步和異步
結果的通知機制。自己問還是別人通知。
同步:主動等待結果的返回。如阻塞等待,輪詢(同步非阻塞)。
異步:被動等待結果的返回。如 消息回調。

阻塞和非阻塞
結果返回以前,調用方的狀態。等還是不等。
阻塞:結果返回以前,什麼也不幹。

非阻塞:在結果返回以前,可以先做一些其他事情。

Monitor鎖

下面所說的獲取monitor鎖都是指的先使用synchronized獲取對象鎖
不應該叫synchronized(mutex)爲鎖,而應該是某個線程獲取了與mutex關聯的monitor鎖。

wait 與 notify

wait 理解成線程在等待直到該對象可用。(被notify後就不再等待)

notify理解成線程通知該對象可用。

使用wait的注意事項

  1. wait必須在同步方法中使用,因爲wait必須由擁有monitor(已用synchronize獲取鎖)的線程調用。

  2. wait可以被中斷,爲了防止wait被interrupt喚醒,wait方法需要在循環中使用。

  3. 使用wait後自動釋放線程對應的鎖。–release ownership of this monitor

  4. wait會等待直到其他線程調用notify/notifyAll喚醒。–waits until anthoer thread notifies threads waiting on this object’s monitor to wake up…

  5. 被notify/notifyAll喚醒後會重新獲得鎖的擁有權,然後接着執行。–re-obtain ownership of the monitor and resumes execution.

  6. 線程調用wait後, 會加入與之對應的wait set.每個對象都有一個與之對應的wait set.使用notify會將其中一個彈出,notifyAll彈出所有線程。(C5.3.2)

    Causes the current thread to wait until another thread invokes the
    * {@link java.lang.Object#notify()} method or the
    * {@link java.lang.Object#notifyAll()} method for this object.
    * In other words, this method behaves exactly as if it simply
    * performs the call {@code wait(0)}.
    *


    * The current thread must own this object’s monitor. The thread
    * releases ownership of this monitor and waits until another thread
    * notifies threads waiting on this object’s monitor to wake up
    * either through a call to the {@code notify} method or the
    * {@code notifyAll} method. The thread then waits until it can
    * re-obtain ownership of the monitor and resumes execution.
    * As in the one argument version, interrupts and spurious wakeups are
    * possible, and this method should always be used in a loop:
    * synchronized (obj) {
    * while (<condition does not hold>)
    * obj.wait();
    * … // Perform action appropriate to condition
    * }
    * This method should only be called by a thread that is the owner
    * of this object’s monitor. See the {@code notify} method for a
    * description of the ways in which a thread can become the owner of a monitor.

使用notify的注意

  1. 必須在同步方法中使用wait、notify,因爲他們的使用前提都是持有monitor所有權。

  2. 同步代碼塊的monitor必須與執行 wait 、notify的對象一致,也就是說對哪個對象同步,才能調用那個對象的 wait、notify。

例子:

若不是用的notifyAll, 則不能用於多線程環境

在這裏插入圖片描述
在這裏插入圖片描述
while而不是if中調用wait!否則一旦被interrupt,會跳過判斷繼續執行。如
在這裏插入圖片描述

測試主動interrupt對if中使用wait的影響

這裏主動interrupt,可見當producer被interrupt後,producer就略過了判斷,繼續添加了一個event

test interrupt

wait與sleep的

  • 相同:
    使線程阻塞
    可以中斷
  • 不同:
    wait是Object的方法,sleep是Thread的
    wait必須要在同步代碼塊中執行。
    wait會釋放monitor的鎖,sleep不會
    sleep短暫休眠後會退出阻塞?(TODO)wait(沒有指定時間的話)必須被中斷纔會退出阻塞。

synchronized的缺點

  1. 無法中斷
    synchronized不像sleep和wait那樣,可以被中斷。

  2. 沒有等待時間
    其他線程獲取鎖的擁有權必須要等待鎖的擁有者(線程)釋放後才能執行。

利用wait、notify實現可中斷的BooleanLock

p96-104
一旦從wait中被喚醒則有機會檢查lock是否爲false,爲false則修改獲取鎖的線程cureentLockThread爲自己,並設置lock爲true.防止其他線程繼續爭搶。
如果wait超時會報錯,notify後超時 也主動拋錯。

關鍵代碼

在這裏插入圖片描述

從wait中被notify或者等待超時後,會因爲while(locked),locked爲false,說明沒有線程持有monitor的擁有權,因此跳出while設置locked=true;this.currentThread=currentThread();
在這裏插入圖片描述
優化,超時後清除blackList
在這裏插入圖片描述

發佈於2019年7月7日 16:40:43

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