Java并发与锁设计实现详述 - Java中的Condition
關于等待通知機制,在Java中主要有兩種方式。一種是基于wait/notify方法集合synchronized關鍵字實現的,這在上一篇文章《Java并發與鎖設計實現詳述(10)- Java中的等待/通知機制》中已經講述了,另一種方法是Condition結合Lock來實現。
下面先把這兩種方式進行一個簡單的對比。
| 前置條件 | 在使用之前獲取對象的鎖 | 調用Lock.lock獲取鎖; 調用Lock.newCondition獲取Condition對象; |
| 調用方式 | 直接調用,如:object.wait() | 直接調用,如condition.await() |
| 等待隊列個數 | 一個 | 多個 |
| 當前線程釋放鎖并進入等待狀態 | 支持 | 支持 |
當前線程釋放鎖并進入等待狀態, 在等待狀態不響應中斷 | 不支持 | 支持 |
| 當前線程釋放鎖并進入超時等待狀態 | 支持 | 支持 |
當前線程釋放鎖并進入超時等待狀態, 在超時等待狀態不響應中斷 | 不支持 | 支持 |
| 喚醒等待隊列中的一個線程 | 支持 | 支持 |
| 喚醒等待隊列中的全部線程 | 支持 | 支持 |
從上面的對比來看,兩種方式功能基本一樣,只是在響應中斷的場景下有細微區別。
由于前文已經講過基于Object Monitor Methods實現的等待通知機制,在本文將講述另一種實現,即基于Condition接口的實現方式。
Condition的接口與示例:
Condition接口定義了等待/通知兩種類型的方法,在線程調用這些方法時,需要提前獲取Condition對象關聯的鎖(在基于wait/notify方法實現的方案中需要獲取的是對象鎖)。
Condition對象是需要關聯Lock對象的,經調用Lock對象的newCondition()對象創建而來,也就是說Condition的使用是需要依賴Lock對象的。
下面是使用Condition的示范代碼:
private Lock lock = new ReentrantLock();
?? ?private Condition condition = lock.newCondition();
?
?? ?public void conditionAwait() throws InterruptedException {
?? ??? ?lock.lock();
?? ??? ?try {
?? ??? ??? ?condition.await();
?? ??? ?} finally {
?? ??? ??? ?lock.unlock();
?? ??? ?}
?? ?}
?
?? ?public void conditionSignal() {
?? ??? ?lock.lock();
?? ??? ?try {
?? ??? ??? ?condition.signal();//condition.signalAll();
?? ??? ?} finally {
?? ??? ??? ?lock.unlock();
?? ??? ?}
?? ?}
下面是關于Condition方法的一些簡單說明:
| await() | 當前線程進入等待狀態直到被通知(signal)或者中斷; 當前線程進入運行狀態并從await()方法返回的場景包括: (1)其他線程調用相同Condition對象的signal/signalAll方法,并且當前線程被喚醒; (2)其他線程調用interrupt方法中斷當前線程; |
| awaitUninterruptibly() | 當前線程進入等待狀態直到被通知,在此過程中對中斷信號不敏感,不支持中斷當前線程 |
| awaitNanos(long) | 當前線程進入等待狀態,直到被通知、中斷或者超時。如果返回值小于等于0,可以認定就是超時了 |
| awaitUntil(Date) | 當前線程進入等待狀態,直到被通知、中斷或者超時。如果沒到指定時間被通知,則返回true,否則返回false |
| signal() | 喚醒一個等待在Condition上的線程,被喚醒的線程在方法返回前必須獲得與Condition對象關聯的鎖 |
| signalAll() | 喚醒所有等待在Condition上的線程,能夠從await()等方法返回的線程必須先獲得與Condition對象關聯的鎖 |
下面通過一個示例來簡單看看Condition是如何實現線程等待/通知機制的。
package?com.majing.java.concurrent;import?java.util.Arrays; import?java.util.concurrent.locks.Condition; import?java.util.concurrent.locks.Lock; import?java.util.concurrent.locks.ReentrantLock;public?class?BoundedQueue?{private?Integer[]?items;//定義為數組,在創建對象時就確定容量private?Lock?lock?=?new?ReentrantLock();private?Condition?notEmpty?=?lock.newCondition();private?Condition?notFull?=?lock.newCondition();private?int?count;private?int?addIndex,removeIndex;public?BoundedQueue(int?size){items?=?new?Integer[size];}public?void?add(Integer?object)?throws?InterruptedException{lock.lock();try{while(count==items.length){notFull.await();}items[addIndex]?=?object;if(++addIndex==items.length){addIndex?=?0;}count++;System.out.println(Thread.currentThread()+"?插入一個元素,數組為:"+Arrays.toString(items));notEmpty.signal();}finally{lock.unlock();}}@SuppressWarnings("unchecked")public?Integer?remove()?throws?InterruptedException{lock.lock();try{while(count==0){notEmpty.await();}Integer?temp?=?items[removeIndex];items[removeIndex]?=?null;System.out.println(Thread.currentThread()+"?移除一個元素,數組為:"+Arrays.toString(items));if(++removeIndex==items.length){removeIndex=0;}count--;notFull.signal();return?temp;}finally{lock.unlock();}} }上面是有界隊列實現,下面寫個簡單的測試用例來測試這個有界隊列是否可靠。
package?com.majing.java.test;import?java.util.Random;import?com.majing.java.concurrent.BoundedQueue;public?class?Test?{private?static?final?Random?random?=?new?Random(System.currentTimeMillis());public?static?void?main(String[]?args)?throws?InterruptedException?{BoundedQueue?queue?=?new?BoundedQueue(5);for(int?i=1;i<=20;i++){Thread?thread?=?new?Thread(new?Producter(queue),String.valueOf(i));thread.start();}for(int?i=1;i<=20;i++){Thread?thread?=?new?Thread(new?Consumer(queue),String.valueOf(i));thread.start();}}static?class?Producter?implements?Runnable{private?BoundedQueue?queue;public?Producter(BoundedQueue?queue){this.queue?=?queue;}public?void?produce()?throws?InterruptedException{queue.add(new?Integer(random.nextInt(100)));}@Overridepublic?void?run()?{try?{produce();}?catch?(InterruptedException?e)?{e.printStackTrace();}}}static?class?Consumer?implements?Runnable{private?BoundedQueue?queue;public?Consumer(BoundedQueue?queue){this.queue?=?queue;}public?Integer?remove()?throws?InterruptedException{return?queue.remove();}@Overridepublic?void?run()?{try?{remove();}?catch?(InterruptedException?e)?{e.printStackTrace();}}} }運行上面的代碼,結果如下:
Thread[1,5,main] 插入一個元素,數組為:[92, null, null, null, null]
Thread[2,5,main] 插入一個元素,數組為:[92, 87, null, null, null]
Thread[3,5,main] 插入一個元素,數組為:[92, 87, 19, null, null]
Thread[4,5,main] 插入一個元素,數組為:[92, 87, 19, 88, null]
Thread[5,5,main] 插入一個元素,數組為:[92, 87, 19, 88, 22]
Thread[1,5,main] 移除一個元素,數組為:[null, 87, 19, 88, 22]
Thread[2,5,main] 移除一個元素,數組為:[null, null, 19, 88, 22]
Thread[6,5,main] 插入一個元素,數組為:[23, null, 19, 88, 22]
Thread[7,5,main] 插入一個元素,數組為:[23, 26, 19, 88, 22]
Thread[3,5,main] 移除一個元素,數組為:[23, 26, null, 88, 22]
Thread[4,5,main] 移除一個元素,數組為:[23, 26, null, null, 22]
Thread[9,5,main] 插入一個元素,數組為:[23, 26, 30, null, 22]
Thread[8,5,main] 插入一個元素,數組為:[23, 26, 30, 83, 22]
Thread[5,5,main] 移除一個元素,數組為:[23, 26, 30, 83, null]
Thread[6,5,main] 移除一個元素,數組為:[null, 26, 30, 83, null]
Thread[7,5,main] 移除一個元素,數組為:[null, null, 30, 83, null]
Thread[10,5,main] 插入一個元素,數組為:[null, null, 30, 83, 25]
Thread[11,5,main] 插入一個元素,數組為:[13, null, 30, 83, 25]
Thread[12,5,main] 插入一個元素,數組為:[13, 30, 30, 83, 25]
Thread[9,5,main] 移除一個元素,數組為:[13, 30, null, 83, 25]
Thread[8,5,main] 移除一個元素,數組為:[13, 30, null, null, 25]
Thread[13,5,main] 插入一個元素,數組為:[13, 30, 9, null, 25]
Thread[14,5,main] 插入一個元素,數組為:[13, 30, 9, 4, 25]
Thread[10,5,main] 移除一個元素,數組為:[13, 30, 9, 4, null]
Thread[15,5,main] 插入一個元素,數組為:[13, 30, 9, 4, 85]
Thread[11,5,main] 移除一個元素,數組為:[null, 30, 9, 4, 85]
Thread[13,5,main] 移除一個元素,數組為:[null, null, 9, 4, 85]
Thread[16,5,main] 插入一個元素,數組為:[20, null, 9, 4, 85]
Thread[18,5,main] 插入一個元素,數組為:[20, 71, 9, 4, 85]
Thread[14,5,main] 移除一個元素,數組為:[20, 71, null, 4, 85]
Thread[17,5,main] 插入一個元素,數組為:[20, 71, 50, 4, 85]
Thread[16,5,main] 移除一個元素,數組為:[20, 71, 50, null, 85]
Thread[19,5,main] 插入一個元素,數組為:[20, 71, 50, 3, 85]
Thread[17,5,main] 移除一個元素,數組為:[20, 71, 50, 3, null]
Thread[18,5,main] 移除一個元素,數組為:[null, 71, 50, 3, null]
Thread[19,5,main] 移除一個元素,數組為:[null, null, 50, 3, null]
Thread[20,5,main] 插入一個元素,數組為:[null, null, 50, 3, 8]
Thread[20,5,main] 移除一個元素,數組為:[null, null, null, 3, 8]
Thread[12,5,main] 移除一個元素,數組為:[null, null, null, null, 8]
Thread[15,5,main] 移除一個元素,數組為:[null, null, null, null, null]
轉載于:https://blog.51cto.com/12104971/2168932
總結
以上是生活随笔為你收集整理的Java并发与锁设计实现详述 - Java中的Condition的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Madplay移植到mini2440开发
- 下一篇: app测试之耗电量测试