執行緒間通訊
等待/通知機制
wait()
和notify()
: wait
使執行緒停止執行,notify
使停止的執行緒繼續執行。
注意事項:
wait()
自動鎖放物件鎖;notify()
不釋放;它們必須存在與同步塊中。- wait 後執行緒會進入等待池,需要由同一物件的 notify 方法喚醒。
- 當執行緒處於wait狀態時,呼叫
interrup()
方法會出現異常。 - notify()隨機喚醒執行緒,
notifyAll()
喚醒全部wait執行緒. wait(n)
,使執行緒等待一段時間,如果沒被喚醒,超過時間自動喚醒。
可以用wait()
和notify()
實現生產者和消費者
- 假死:所有執行緒都呈WAITING狀態。
- 原因:notify喚醒的是異類,如“生產者”喚醒“生產者”。
- 解決:將
notify()
改為notifyAll()
通過管道進行執行緒間通訊:一個執行緒傳送資料到輸出管道,另一個執行緒從輸入管道中讀資料。
- 位元組流:
PipedInputStream
和PipedOutputStream
- 字元流:
PipedReader
和PipedWriter
方法join的使用
join()
:使當前執行緒堵塞,等待執行緒物件銷燬後,再執行當前執行緒後面的程式碼。
join()
與interrupt()
方法如果彼此遇到,則會出現異常。join(long)
可設定等待的時間。注意:join(long)
內部使用wait(long)
實現,所以join(long)
會釋放鎖;而Thread.sleep(long)
不會釋放鎖。
ThreadLocal的使用
ThreadLocal
類:讓每個執行緒可以繫結自己的值- 解決
get()
返回null的問題:覆蓋initialValue()
方法使變數具有初始值。 InheritableThreadLocal
類可在子執行緒中取得父執行緒繼承下來的值。- 還可以對子執行緒繼承下來的值進行修改。
Lock的使用
使用ReentrantLock類
基本用法:
- 同步:
lock()
讓執行緒持有了“物件監視器”,和synchronized一樣,執行緒之間還是順序執行的。 - 等待/通知:
condition.await()
等待;condition.siganl()
通知。注意呼叫condition.await()
前須先呼叫lock.lock()
。它比wait更靈活,因為它可以用不同的condition
物件實現通知部分執行緒。
公平鎖和非公平鎖
- 公平鎖:
new ReentranLock(true)
獲取鎖是先進先得的 - 非公平鎖:
new ReentranLock(false)
獲取鎖是隨機的
一些方法:
int getHoldCount()
查詢當前執行緒保持此鎖定的個數,也就是呼叫lock()方法的次數。int getQueueLength()
返回正在等待獲取此鎖定的執行緒估計數int getWaitQueueLength(Condition condition)
返回等待與此鎖定相關的給定條件Conditon的執行緒估計數boolean hasQueueThread(Thread thread)
查詢指定的執行緒是否正在等待獲取此鎖定boolean hasQueueThreads()
查詢是否有執行緒正在等待獲取此鎖定boolean hasWaiters(Condition)
查詢是否有執行緒正在等待與此鎖定有關的condition條件boolean isFair()
判斷是不是公平鎖boolean isHeldByCurrentThread()
查詢當前執行緒是否保持此鎖定boolean isLocked()
查詢此鎖定是否由任意執行緒保持void lockInterruptibly()
如果當前執行緒未被中斷,則獲取鎖定,如果已經被中斷則出現異常boolean tryLock()
僅在呼叫時鎖定未被另一個執行緒保持的情況下,才獲取該鎖定boolean tryLock(long timeout,TimeUnit unit)
如果鎖定在給定等待時間內沒有被另一個執行緒保持,且當前執行緒未被中斷,則獲取該鎖定void awaitUninterruptibly()
await狀態時呼叫thread.interrupt()不會報錯
使用ReentrantReadWriteLock類
ReentrantLock
類完全互斥,即同一時間只有一個執行緒可執行lock後面的任務。
ReentrantReadWriteLock
特點:
- 讀讀共享
- 寫寫互斥
- 寫讀互斥
- 讀寫互斥