這篇文章主要講解了Java并發(fā)之Condition的詳細(xì)解析,內(nèi)容清晰明了,對此有興趣的小伙伴可以學(xué)習(xí)一下,相信大家閱讀完之后會有幫助。
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),天心企業(yè)網(wǎng)站建設(shè),天心品牌網(wǎng)站建設(shè),網(wǎng)站定制,天心網(wǎng)站建設(shè)報價,網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,天心網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競爭力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。
在使用Lock之前,我們使用的最多的同步方式應(yīng)該是synchronized關(guān)鍵字來實現(xiàn)同步方式了。配合Object的wait()、notify()系列方法可以實現(xiàn)等待/通知模式。Condition接口也提供了類似Object的監(jiān)視器方法,與Lock配合可以實現(xiàn)等待/通知模式,但是這兩者在使用方式以及功能特性上還是有差別的。Object和Condition接口的一些對比。摘自《Java并發(fā)編程的藝術(shù)》

一、Condition接口介紹和示例
首先我們需要明白condition對象是依賴于lock對象的,意思就是說condition對象需要通過lock對象進(jìn)行創(chuàng)建出來(調(diào)用Lock對象的newCondition()方法)。consition的使用方式非常的簡單。但是需要注意在調(diào)用方法前獲取鎖。
package com.ydl.test.juc;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionUseCase {
public Lock lock = new ReentrantLock();
public Condition condition = lock.newCondition();
public static void main(String[] args) {
ConditionUseCase useCase = new ConditionUseCase();
ExecutorService executorService = Executors.newFixedThreadPool (2);
executorService.execute(new Runnable() {
@Override
public void run() {
useCase.conditionWait();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
useCase.conditionSignal();
}
});
}
public void conditionWait() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "拿到鎖了");
System.out.println(Thread.currentThread().getName() + "等待信號");
condition.await();
System.out.println(Thread.currentThread().getName() + "拿到信號");
}catch (Exception e){
}finally {
lock.unlock();
}
}
public void conditionSignal() {
lock.lock();
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName() + "拿到鎖了");
condition.signal();
System.out.println(Thread.currentThread().getName() + "發(fā)出信號");
}catch (Exception e){
}finally {
lock.unlock();
}
}
}pool-1-thread-1拿到鎖了
pool-1-thread-1等待信號
pool-1-thread-2拿到鎖了
pool-1-thread-2發(fā)出信號
pool-1-thread-1拿到信號
如示例所示,一般都會將Condition對象作為成員變量。當(dāng)調(diào)用await()方法后,當(dāng)前線程會釋放鎖并在此等待,而其他線程調(diào)用Condition對象的signal()方法,通知當(dāng)前線程后,當(dāng)前線程才從await()方法返回,并且在返回前已經(jīng)獲取了鎖。
二、Condition接口常用方法
condition可以通俗的理解為條件隊列。當(dāng)一個線程在調(diào)用了await方法以后,直到線程等待的某個條件為真的時候才會被喚醒。這種方式為線程提供了更加簡單的等待/通知模式。Condition必須要配合鎖一起使用,因為對共享狀態(tài)變量的訪問發(fā)生在多線程環(huán)境下。一個Condition的實例必須與一個Lock綁定,因此Condition一般都是作為Lock的內(nèi)部實現(xiàn)。
await():造成當(dāng)前線程在接到信號或被中斷之前一直處于等待狀態(tài)。
await(long time, TimeUnit unit):造成當(dāng)前線程在接到信號、被中斷或到達(dá)指定等待時間之前一直處于等待狀態(tài)。
awaitNanos(long nanosTimeout):造成當(dāng)前線程在接到信號、被中斷或到達(dá)指定等待時間之前一直處于等待狀態(tài)。返回值表示剩余時間,如果在nanosTimesout之前喚醒,那么返回值 = nanosTimeout - 消耗時間,如果返回值 <= 0 ,則可以認(rèn)定它已經(jīng)超時了。
awaitUninterruptibly():造成當(dāng)前線程在接到信號之前一直處于等待狀態(tài)。【注意:該方法對中斷不敏感】。
awaitUntil(Date deadline):造成當(dāng)前線程在接到信號、被中斷或到達(dá)指定最后期限之前一直處于等待狀態(tài)。如果沒有到指定時間就被通知,則返回true,否則表示到了指定時間,返回返回false。
signal():喚醒一個等待線程。該線程從等待方法返回前必須獲得與Condition相關(guān)的鎖。
signal()All:喚醒所有等待線程。能夠從等待方法返回的線程必須獲得與Condition相關(guān)的鎖。
三、Condition接口原理簡單解析
Condition是AQS的內(nèi)部類。每個Condition對象都包含一個隊列(等待隊列)。等待隊列是一個FIFO的隊列,在隊列中的每個節(jié)點都包含了一個線程引用,該線程就是在Condition對象上等待的線程,如果一個線程調(diào)用了Condition.await()方法,那么該線程將會釋放鎖、構(gòu)造成節(jié)點加入等待隊列并進(jìn)入等待狀態(tài)。等待隊列的基本結(jié)構(gòu)如下所示。

等待分為首節(jié)點和尾節(jié)點。當(dāng)一個線程調(diào)用Condition.await()方法,將會以當(dāng)前線程構(gòu)造節(jié)點,并將節(jié)點從尾部加入等待隊列。新增節(jié)點就是將尾部節(jié)點指向新增的節(jié)點。節(jié)點引用更新本來就是在獲取鎖以后的操作,所以不需要CAS保證。同時也是線程安全的操作。
3.2、等待
當(dāng)線程調(diào)用了await方法以后。線程就作為隊列中的一個節(jié)點被加入到等待隊列中去了。同時會釋放鎖的擁有。當(dāng)從await方法返回的時候。一定會獲取condition相關(guān)聯(lián)的鎖。當(dāng)?shù)却犃兄械墓?jié)點被喚醒的時候,則喚醒節(jié)點的線程開始嘗試獲取同步狀態(tài)。如果不是通過 其他線程調(diào)用Condition.signal()方法喚醒,而是對等待線程進(jìn)行中斷,則會拋出InterruptedException異常信息。
3.3、通知
調(diào)用Condition的signal()方法,將會喚醒在等待隊列中等待最長時間的節(jié)點(條件隊列里的首節(jié)點),在喚醒節(jié)點前,會將節(jié)點移到同步隊列中。當(dāng)前線程加入到等待隊列中如圖所示:

在調(diào)用signal()方法之前必須先判斷是否獲取到了鎖。接著獲取等待隊列的首節(jié)點,將其移動到同步隊列并且利用LockSupport喚醒節(jié)點中的線程。節(jié)點從等待隊列移動到同步隊列如下圖所示:

被喚醒的線程將從await方法中的while循環(huán)中退出。隨后加入到同步狀態(tài)的競爭當(dāng)中去。成功獲取到競爭的線程則會返回到await方法之前的狀態(tài)。
四、總結(jié)
調(diào)用await方法后,將當(dāng)前線程加入Condition等待隊列中。當(dāng)前線程釋放鎖。否則別的線程就無法拿到鎖而發(fā)生死鎖。自旋(while)掛起,不斷檢測節(jié)點是否在同步隊列中了,如果是則嘗試獲取鎖,否則掛起。當(dāng)線程被signal方法喚醒,被喚醒的線程將從await()方法中的while循環(huán)中退出來,然后調(diào)用acquireQueued()方法競爭同步狀態(tài)。
五、利用Condition實現(xiàn)生產(chǎn)者消費者模式
import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BoundedQueue {
private LinkedList<Object> buffer; //生產(chǎn)者容器
private int maxSize ; //容器最大值是多少
private Lock lock;
private Condition fullCondition;
private Condition notFullCondition;
BoundedQueue(int maxSize){
this.maxSize = maxSize;
buffer = new LinkedList<Object>();
lock = new ReentrantLock();
fullCondition = lock.newCondition();
notFullCondition = lock.newCondition();
}
/**
* 生產(chǎn)者
* @param obj
* @throws InterruptedException
*/
public void put(Object obj) throws InterruptedException {
lock.lock(); //獲取鎖
try {
while (maxSize == buffer.size()){
notFullCondition.await(); //滿了,添加的線程進(jìn)入等待狀態(tài)
}
buffer.add(obj);
fullCondition.signal(); //通知
} finally {
lock.unlock();
}
}
/**
* 消費者
* @return
* @throws InterruptedException
*/
public Object get() throws InterruptedException {
Object obj;
lock.lock();
try {
while (buffer.size() == 0){ //隊列中沒有數(shù)據(jù)了 線程進(jìn)入等待狀態(tài)
fullCondition.await();
}
obj = buffer.poll();
notFullCondition.signal(); //通知
} finally {
lock.unlock();
}
return obj;
}
}看完上述內(nèi)容,是不是對Java并發(fā)之Condition的詳細(xì)解析有進(jìn)一步的了解,如果還想學(xué)習(xí)更多內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
網(wǎng)頁名稱:Java并發(fā)之Condition的詳細(xì)解析
網(wǎng)頁網(wǎng)址:http://www.chinadenli.net/article18/iiidgp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站、網(wǎng)站設(shè)計、ChatGPT、搜索引擎優(yōu)化、移動網(wǎng)站建設(shè)、小程序開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)