1. 程式人生 > >java Condition多執行緒之間通訊

java Condition多執行緒之間通訊

執行緒間通訊Condition

Condition可以替代傳統的執行緒間通訊,await()替換wait(),用signal()替換notify(),用signalAll()替換notifyAll()。

——為什麼方法名不直接叫wait()/notify()/nofityAll()?因為Object的這幾個方法是final的,不可重寫!

傳統執行緒的通訊方式,Condition都可以實現。

注意,Condition是被繫結到Lock上的,要建立一個Lock的Condition必須用newCondition()方法。

Condition的強大之處在於它可以為多個執行緒間建立不同的Condition


看JDK文件中的一個例子:假定有一個繫結的緩衝區,它支援puttake方法。如果試圖在空的緩衝區上執行take操作,則在某一個項變得可用之前,執行緒將一直阻塞;如果試圖在滿的緩衝區上執行put操作,則在有空間變得可用之前,執行緒將一直阻塞。我們喜歡在單獨的等待 set 中儲存put執行緒和take執行緒,這樣就可以在緩衝區中的項或空間變得可用時利用最佳規劃,一次只通知一個執行緒。可以使用兩個Condition例項來做到這一點。

——其實就是java.util.concurrent.ArrayBlockingQueue的功能


  1. class BoundedBuffer {  
  2.   final
     Lock lock = new ReentrantLock();          //鎖物件
  3.   final Condition notFull  = lock.newCondition(); //寫執行緒鎖
  4.   final Condition notEmpty = lock.newCondition(); //讀執行緒鎖
  5.   final Object[] items = new Object[100];//快取佇列
  6.   int putptr;  //寫索引
  7.   int takeptr; //讀索引
  8.   int count;   //佇列中資料數目
  9.   //寫
  10.   publicvoid put(Object x) throws
     InterruptedException {  
  11.     lock.lock(); //鎖定
  12.     try {  
  13.       // 如果佇列滿,則阻塞<寫執行緒>
  14.       while (count == items.length) {  
  15.         notFull.await();   
  16.       }  
  17.       // 寫入佇列,並更新寫索引
  18.       items[putptr] = x;   
  19.       if (++putptr == items.length) putptr = 0;   
  20.       ++count;  
  21.       // 喚醒<讀執行緒>
  22.       notEmpty.signal();   
  23.     } finally {   
  24.       lock.unlock();//解除鎖定 
  25.     }   
  26.   }  
  27.   //讀 
  28.   public Object take() throws InterruptedException {   
  29.     lock.lock(); //鎖定 
  30.     try {  
  31.       // 如果佇列空,則阻塞<讀執行緒>
  32.       while (count == 0) {  
  33.          notEmpty.await();  
  34.       }  
  35.       //讀取佇列,並更新讀索引
  36.       Object x = items[takeptr];   
  37.       if (++takeptr == items.length) takeptr = 0;  
  38.       --count;  
  39.       // 喚醒<寫執行緒>
  40.       notFull.signal();   
  41.       return x;   
  42.     } finally {   
  43.       lock.unlock();//解除鎖定 
  44.     }   
  45.   }   


優點:

假設快取佇列中已經存滿,那麼阻塞的肯定是寫執行緒,喚醒的肯定是讀執行緒,相反,阻塞的肯定是讀執行緒,喚醒的肯定是寫執行緒。

那麼假設只有一個Condition會有什麼效果呢?快取佇列中已經存滿,這個Lock不知道喚醒的是讀執行緒還是寫執行緒了,如果喚醒的是讀執行緒,皆大歡喜,如果喚醒的是寫執行緒,那麼執行緒剛被喚醒,又被阻塞了,這時又去喚醒,這樣就浪費了很多時間。