使用JUC並發工具包的Lock和Condition,實現生產者和消費者問題中的有界緩衝

來源:互聯網
上載者:User

標籤:生產者和消費者   lock和condition   wait和notify   條件謂詞   條件隊列   

JDK5.0之前,用java實現生產者和消費者的唯一方式就是使用synchronized內建鎖和wait/notify條件通知機制。JDK5.0之後提供了顯示鎖Lock和條件隊列Condition,與內建鎖和內建條件隊列相對應,但是顯示的鎖和條件隊列,功能更強大,更靈活。此外JDK5.0之後還提供了大量很有用的並發工具類,如BlockingQueue等,基於這些資料結構,能夠方便、快速、高效的構建自己應用需要的效果。這裡我們簡單使用下顯示鎖和條件隊列,來類比有界緩衝的實現,功能類似於JDK內建的阻塞隊列BlockingQueue。

 

生產者和消費者問題,這裡不再介紹了,網上有很多資料。這裡提一個概念:條件謂詞。條件謂詞就是使某個依賴狀態的操作能夠成功的前提條件。對於有界緩衝來說,只有當緩衝不為空白,消費者才能get資料,否則消費者必須等待;只有當緩衝未滿,生產者才能put資料,否者生產者必須等待。對於生產者線程來說,它的條件謂詞是"緩衝未滿";對於消費者來說,它的條件謂詞是"緩衝非空"。為什麼要提到條件謂詞呢?因為如果我們找到了所有的條件謂詞,才能夠清楚線程之間的關係和依賴,才能實現正確的等待和喚醒。《java並發編程實踐》一書14.2節很好地闡了鎖、條件隊列、條件謂詞這3者之間的聯絡。

 

首先我們使用最原始的synchronized和wait/notify機制,實現生產者和消費者問題中的有界緩衝,代碼如下:

package waitnotify;import java.util.ArrayList;import java.util.List;public class InSideLock{// 保護共用資料的鎖private Object lockObj = new Object();// 緩衝池private List<String> pools = null;// 最大容量private int CAPACITY = 0;public InSideLock(int capacity){this.pools = new ArrayList<String>(capacity);this.CAPACITY = capacity;}public void put(String e) throws InterruptedException{synchronized (lockObj){while (pools.size() == CAPACITY){// 調用wait,必須要持有鎖,而且必須在while迴圈中測試條件lockObj.wait();}pools.add(e);lockObj.notifyAll();}}public String get() throws InterruptedException{synchronized (lockObj){while (pools.size() == 0){lockObj.wait();}String value = pools.remove(0);lockObj.notifyAll();return value;}}}


使用顯示鎖和條件隊列代碼如下:

package waitnotify;import java.util.ArrayList;import java.util.List;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class VisibleLock{// 保護共用資料的鎖private Lock mainLock = new ReentrantLock();// 消費者等待的非空謂詞private Condition notEmpty = mainLock.newCondition();// 生產者等待的非滿謂詞private Condition notFull = mainLock.newCondition();private List<String> pools = null;private int CAPACITY = 0;public VisibleLock(int capacity){this.pools = new ArrayList<String>(capacity);this.CAPACITY = capacity;}public void put(String e) throws InterruptedException{mainLock.lock();try{while (pools.size() == CAPACITY){notFull.await();}pools.add(e);// 使用條件隊列的顯示API,特別注意這裡不能使用notifynotEmpty.signalAll();} finally{mainLock.unlock();}}public String get() throws InterruptedException{mainLock.lock();try{while (pools.size() == 0){notEmpty.await();}notFull.signalAll();return pools.remove(0);} finally{mainLock.unlock();}}}

下面是測試生產者和消費者的代碼:

package waitnotify;public class Test{public static void main(String[] args) throws Exception{final InSideLock pc = new InSideLock(10);Thread t1 = new Thread(new Runnable() {@Overridepublic void run(){while (true){try{System.out.println("get=" + pc.get());} catch (InterruptedException e){}}}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run(){while (true){try{long time = System.currentTimeMillis();System.out.println("put=" + time);pc.put(time + "");} catch (InterruptedException e){}}}});t1.start();t2.start();}}

可以發現使用內建鎖和內建條件隊列,與使用顯示鎖和顯示條件隊列代碼幾乎是一樣的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.