java Condition多執行緒之間通訊
阿新 • • 發佈:2019-01-26
執行緒間通訊Condition
Condition可以替代傳統的執行緒間通訊,用await()替換wait(),用signal()替換notify(),用signalAll()替換notifyAll()。
——為什麼方法名不直接叫wait()/notify()/nofityAll()?因為Object的這幾個方法是final的,不可重寫!
傳統執行緒的通訊方式,Condition都可以實現。
注意,Condition是被繫結到Lock上的,要建立一個Lock的Condition必須用newCondition()方法。
Condition的強大之處在於它可以為多個執行緒間建立不同的Condition
看JDK文件中的一個例子:假定有一個繫結的緩衝區,它支援put和take方法。如果試圖在空的緩衝區上執行take操作,則在某一個項變得可用之前,執行緒將一直阻塞;如果試圖在滿的緩衝區上執行put操作,則在有空間變得可用之前,執行緒將一直阻塞。我們喜歡在單獨的等待
set 中儲存put執行緒和take執行緒,這樣就可以在緩衝區中的項或空間變得可用時利用最佳規劃,一次只通知一個執行緒。可以使用兩個Condition
例項來做到這一點。
——其實就是java.util.concurrent.ArrayBlockingQueue的功能
- class BoundedBuffer {
-
final
- final Condition notFull = lock.newCondition(); //寫執行緒鎖
- final Condition notEmpty = lock.newCondition(); //讀執行緒鎖
- final Object[] items = new Object[100];//快取佇列
- int putptr; //寫索引
- int takeptr; //讀索引
- int count; //佇列中資料數目
- //寫
-
publicvoid put(Object x) throws
- lock.lock(); //鎖定
- try {
- // 如果佇列滿,則阻塞<寫執行緒>
- while (count == items.length) {
- notFull.await();
- }
- // 寫入佇列,並更新寫索引
- items[putptr] = x;
- if (++putptr == items.length) putptr = 0;
- ++count;
- // 喚醒<讀執行緒>
- notEmpty.signal();
- } finally {
- lock.unlock();//解除鎖定
- }
- }
- //讀
- public Object take() throws InterruptedException {
- lock.lock(); //鎖定
- try {
- // 如果佇列空,則阻塞<讀執行緒>
- while (count == 0) {
- notEmpty.await();
- }
- //讀取佇列,並更新讀索引
- Object x = items[takeptr];
- if (++takeptr == items.length) takeptr = 0;
- --count;
- // 喚醒<寫執行緒>
- notFull.signal();
- return x;
- } finally {
- lock.unlock();//解除鎖定
- }
- }
優點:
假設快取佇列中已經存滿,那麼阻塞的肯定是寫執行緒,喚醒的肯定是讀執行緒,相反,阻塞的肯定是讀執行緒,喚醒的肯定是寫執行緒。
那麼假設只有一個Condition會有什麼效果呢?快取佇列中已經存滿,這個Lock不知道喚醒的是讀執行緒還是寫執行緒了,如果喚醒的是讀執行緒,皆大歡喜,如果喚醒的是寫執行緒,那麼執行緒剛被喚醒,又被阻塞了,這時又去喚醒,這樣就浪費了很多時間。