Condition的使用
jdk1.5提供的api,位于java.util.concurrent.locks 包下,是一個接口, 常用方法有:
| void await() | 造成當前線程在接到信號或被中斷之前一直處于等待狀態。 |
| boolean await(long time, TimeUnit unit) | 造成當前線程在接到信號、被中斷或到達指定等待時間之前一直處于等待狀態。 |
| long awaitNanos(long nanosTimeout) | 造成當前線程在接到信號、被中斷或到達指定等待時間之前一直處于等待狀態。 |
| void awaitUninterruptibly() | 造成當前線程在接到信號之前一直處于等待狀態。 |
| boolean awaitUntil(Date deadline) | 造成當前線程在接到信號、被中斷或到達指定最后期限之前一直處于等待狀態。 |
| void signal() | 喚醒一個等待線程。 |
| void signalAll() | 喚醒所有等待線程。 |
Condition 將 Object 監視器方法(wait、notify 和 notifyAll)分解成截然不同的對象,以便通過將這些對象與任意 Lock 實現組合使用,為每個對象提供多個等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和語句的使用,Condition 替代了 Object 監視器方法的使用。
Condition (條件,也稱為條件隊列或條件變量)為線程提供了一個含義,以便在某個狀態條件現在可能為 true 的另一個線程通知它之前,一直掛起該線程(即讓其“等待”)。因為訪問此共享狀態信息發生在不同的線程中,所以它必須受保護,因此要將某種形式的鎖與該條件相關聯。等待提供一個條件的主要屬性是:以原子方式 釋放相關的鎖,并掛起當前線程,就像 Object.wait 做的那樣。
Condition 實例實質上被綁定到一個鎖上。要為特定 Lock 實例獲得 Condition 實例,請使用其 newCondition() 方法。
官方示例
實現一個緩沖隊列,假定有一個綁定的緩沖區,它支持 put 和 take 方法。如果試圖在空的緩沖區上執行 take 操作,則在某一個項變得可用之前,線程將一直阻塞;如果試圖在滿的緩沖區上執行 put 操作,則在有空間變得可用之前,線程將一直阻塞。我們喜歡在單獨的等待 set 中保存 put 線程和 take 線程,這樣就可以在緩沖區中的項或空間變得可用時利用最佳規劃,一次只通知一個線程。可以使用兩個 Condition 實例來做到這一點。
class BoundedBuffer {final Lock lock = new ReentrantLock();//定義鎖對象//通過鎖對象獲取Condition實例final Condition notFull = lock.newCondition(); //用于控制put操作final Condition notEmpty = lock.newCondition(); //用于控制take操作final Object[] items = new Object[100];//緩沖隊列,初始容量100int putptr, takeptr, count;//分別記錄put,take當前的索引,count用于記錄當前item的個數/*** 往緩沖隊列中添加數據*/public void put(Object x) throws InterruptedException {//上鎖,作用和synchronized一樣,保證代碼同一時刻只有一個線程可以操作,也保證了和take方法的互斥lock.lock();try {while (count == items.length){ notFull.await();//如果隊列滿了,則put線程等待被喚醒}items[putptr] = x; //隊列未滿,則添加數據if (++putptr == items.length) putptr = 0;//添完后,如果記錄讀數據的索引到了最后一個位置,則重置為0++count;//item總數自增notEmpty.signal();//喚醒take線程取數據} finally {lock.unlock();//put操作完后,釋放鎖.}}/*** 從緩沖隊列中取數據*/public Object take() throws InterruptedException {lock.lock();try {while (count == 0){ notEmpty.await();//如果隊列空了,則take線程等待被喚醒}Object x = items[takeptr]; //隊列未空,則取數據if (++takeptr == items.length) takeptr = 0;//取完后,如果記錄取數據的索引到了最后一個位置,則重置為0--count;//item總數自減notFull.signal();//喚醒put線程添加數據return x;//返回取得的數據} finally {lock.unlock();//take操作完后,釋放鎖對象}} }示例2
這個例子是用來實現如下功能,主線程運行5次,然后通知線程1運行5次,然后線程1通知線程2運行5次,接著又由線程2通知主線程運行5次,如此反復執行3次.
分析這個需求的時候,首先應該想到這里一共有3個線程,且每個線程在運行的時候,其它線程不能打擾,也就是說這3個線程需要共用同一個鎖對象,即這3個線程需要訪問同一個共享資源,這里可以有一個很好的解決思路就是將這3個線程各自運行5次的邏輯(方法)封裝到同一個類中.這樣,我們使用Lock或者synchronized的時候,只要鎖對象是同一個,就能保證這3個方法的互斥性了.
然后,需要保證的是這3個線程在執行各自方法的時候是按照一定的順序執行的,這里使用Condition就能很好的解決這個問題,需要用到3個Condition實例,第一個用于主線程與線程1通信,第二個用于線程1和線程2通信,第三個用于線程2和主線程通信.
package com.example;import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;/*** Created by mChenys on 2016/5/15.*/ public class ThreeConditionCommunication {/*** @param args*/public static void main(String[] args) {//定義共享資源final Business business = new Business();//線程2執行new Thread(new Runnable() {@Overridepublic void run() {for (int i = 1; i <= 3; i++) {business.doSub2(i);}}}, "Thread-1").start();//線程3執行new Thread(new Runnable() {@Overridepublic void run() {for (int i = 1; i <= 3; i++) {business.doSub3(i);}}}, "Thread-2").start();//主線程執行for (int i = 1; i <= 3; i++) {business.doMain(i);}}/*** 共享資源*/static class Business {//定義公共鎖Lock lock = new ReentrantLock();Condition condition1 = lock.newCondition();//控制主線程運行Condition condition2 = lock.newCondition();//控制線程2執行Condition condition3 = lock.newCondition();//控制線程3執行private int shouldSub = 1;//標記當前那個線程運行的標記,1為主線程,2為線程2,3為線程3public void doMain(int i) {lock.lock();//上鎖try {while (shouldSub != 1) {try {condition1.await();//主線程等待} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}for (int j = 1; j <= 5; j++) {System.out.println("doMain thread sequence of " + j + ",loop of " + i);}shouldSub = 2;condition2.signal();//喚醒線程2} finally {lock.unlock();//釋放鎖}}public void doSub2(int i) {lock.lock();//上鎖try {while (shouldSub != 2) {try {condition2.await();//線程2等待} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}for (int j = 1; j <= 5; j++) {System.out.println("doSub2 thread sequence of " + j + ",loop of " + i);}shouldSub = 3;condition3.signal();//喚醒線程3} finally {lock.unlock();//釋放鎖}}public void doSub3(int i) {lock.lock();//上鎖try {while (shouldSub != 3) {try {condition3.await();//線程3等待} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}for (int j = 1; j <= 5; j++) {System.out.println("doSub3 thread sequence of " + j + ",loop of " + i);}shouldSub = 1;condition1.signal();//喚醒主線程} finally {lock.unlock();//釋放鎖}}} }運行結果:
doMain thread sequence of 1,loop of 1
doMain thread sequence of 2,loop of 1
doMain thread sequence of 3,loop of 1
doMain thread sequence of 4,loop of 1
doMain thread sequence of 5,loop of 1
doSub2 thread sequence of 1,loop of 1
doSub2 thread sequence of 2,loop of 1
doSub2 thread sequence of 3,loop of 1
doSub2 thread sequence of 4,loop of 1
doSub2 thread sequence of 5,loop of 1
doSub3 thread sequence of 1,loop of 1
doSub3 thread sequence of 2,loop of 1
doSub3 thread sequence of 3,loop of 1
doSub3 thread sequence of 4,loop of 1
doSub3 thread sequence of 5,loop of 1
doMain thread sequence of 1,loop of 2
doMain thread sequence of 2,loop of 2
doMain thread sequence of 3,loop of 2
doMain thread sequence of 4,loop of 2
doMain thread sequence of 5,loop of 2
doSub2 thread sequence of 1,loop of 2
doSub2 thread sequence of 2,loop of 2
doSub2 thread sequence of 3,loop of 2
doSub2 thread sequence of 4,loop of 2
doSub2 thread sequence of 5,loop of 2
doSub3 thread sequence of 1,loop of 2
doSub3 thread sequence of 2,loop of 2
doSub3 thread sequence of 3,loop of 2
doSub3 thread sequence of 4,loop of 2
doSub3 thread sequence of 5,loop of 2
doMain thread sequence of 1,loop of 3
doMain thread sequence of 2,loop of 3
doMain thread sequence of 3,loop of 3
doMain thread sequence of 4,loop of 3
doMain thread sequence of 5,loop of 3
doSub2 thread sequence of 1,loop of 3
doSub2 thread sequence of 2,loop of 3
doSub2 thread sequence of 3,loop of 3
doSub2 thread sequence of 4,loop of 3
doSub2 thread sequence of 5,loop of 3
doSub3 thread sequence of 1,loop of 3
doSub3 thread sequence of 2,loop of 3
doSub3 thread sequence of 3,loop of 3
doSub3 thread sequence of 4,loop of 3
doSub3 thread sequence of 5,loop of 3
從運行結果,可以看出每個線程在執行的時候都是完整完成的,不會受到其它線程的打擾,同時各線程間的運行都是按照事先定好的規則來實現的,這就體現了Condition的強大之處,它能完成wait、notify所不能完成的事情,wait、notify 只能控制2個線程間的通信,而Condition可以控制n個線程間的通信.
總結
以上是生活随笔為你收集整理的Condition的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 完美解决SDWebImage加载多个图片
- 下一篇: 网站域名怎么注册?域名选择注意事项有哪些