国产成人精品亚洲777人妖,欧美日韩精品一区视频,最新亚洲国产,国产乱码精品一区二区亚洲

您的位置:首頁技術(shù)文章
文章詳情頁

詳解Java并發(fā)之Condition

瀏覽:97日期:2022-08-31 15:35:28

在使用Lock之前,我們使用的最多的同步方式應(yīng)該是synchronized關(guān)鍵字來實(shí)現(xiàn)同步方式了。配合Object的wait()、notify()系列方法可以實(shí)現(xiàn)等待/通知模式。Condition接口也提供了類似Object的監(jiān)視器方法,與Lock配合可以實(shí)現(xiàn)等待/通知模式,但是這兩者在使用方式以及功能特性上還是有差別的。Object和Condition接口的一些對比。摘自《Java并發(fā)編程的藝術(shù)》

詳解Java并發(fā)之Condition

一、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可以通俗的理解為條件隊(duì)列。當(dāng)一個(gè)線程在調(diào)用了await方法以后,直到線程等待的某個(gè)條件為真的時(shí)候才會被喚醒。這種方式為線程提供了更加簡單的等待/通知模式。Condition必須要配合鎖一起使用,因?yàn)閷蚕頎顟B(tài)變量的訪問發(fā)生在多線程環(huán)境下。一個(gè)Condition的實(shí)例必須與一個(gè)Lock綁定,因此Condition一般都是作為Lock的內(nèi)部實(shí)現(xiàn)。

await() :造成當(dāng)前線程在接到信號或被中斷之前一直處于等待狀態(tài)。

await(long time, TimeUnit unit) :造成當(dāng)前線程在接到信號、被中斷或到達(dá)指定等待時(shí)間之前一直處于等待狀態(tài)。

awaitNanos(long nanosTimeout) :造成當(dāng)前線程在接到信號、被中斷或到達(dá)指定等待時(shí)間之前一直處于等待狀態(tài)。返回值表示剩余時(shí)間,如果在nanosTimesout之前喚醒,那么返回值 = nanosTimeout - 消耗時(shí)間,如果返回值 <= 0 ,則可以認(rèn)定它已經(jīng)超時(shí)了。

awaitUninterruptibly() :造成當(dāng)前線程在接到信號之前一直處于等待狀態(tài)。【注意:該方法對中斷不敏感】。

awaitUntil(Date deadline) :造成當(dāng)前線程在接到信號、被中斷或到達(dá)指定最后期限之前一直處于等待狀態(tài)。如果沒有到指定時(shí)間就被通知,則返回true,否則表示到了指定時(shí)間,返回返回false。

signal() :喚醒一個(gè)等待線程。該線程從等待方法返回前必須獲得與Condition相關(guān)的鎖。

signal()All :喚醒所有等待線程。能夠從等待方法返回的線程必須獲得與Condition相關(guān)的鎖。

三、Condition接口原理簡單解析

Condition是AQS的內(nèi)部類。每個(gè)Condition對象都包含一個(gè)隊(duì)列(等待隊(duì)列)。等待隊(duì)列是一個(gè)FIFO的隊(duì)列,在隊(duì)列中的每個(gè)節(jié)點(diǎn)都包含了一個(gè)線程引用,該線程就是在Condition對象上等待的線程,如果一個(gè)線程調(diào)用了Condition.await()方法,那么該線程將會釋放鎖、構(gòu)造成節(jié)點(diǎn)加入等待隊(duì)列并進(jìn)入等待狀態(tài)。等待隊(duì)列的基本結(jié)構(gòu)如下所示。

詳解Java并發(fā)之Condition

等待分為首節(jié)點(diǎn)和尾節(jié)點(diǎn)。當(dāng)一個(gè)線程調(diào)用Condition.await()方法,將會以當(dāng)前線程構(gòu)造節(jié)點(diǎn),并將節(jié)點(diǎn)從尾部加入等待隊(duì)列。新增節(jié)點(diǎn)就是將尾部節(jié)點(diǎn)指向新增的節(jié)點(diǎn)。節(jié)點(diǎn)引用更新本來就是在獲取鎖以后的操作,所以不需要CAS保證。同時(shí)也是線程安全的操作。

3.2、等待

當(dāng)線程調(diào)用了await方法以后。線程就作為隊(duì)列中的一個(gè)節(jié)點(diǎn)被加入到等待隊(duì)列中去了。同時(shí)會釋放鎖的擁有。當(dāng)從await方法返回的時(shí)候。一定會獲取condition相關(guān)聯(lián)的鎖。當(dāng)?shù)却?duì)列中的節(jié)點(diǎn)被喚醒的時(shí)候,則喚醒節(jié)點(diǎn)的線程開始嘗試獲取同步狀態(tài)。如果不是通過 其他線程調(diào)用Condition.signal()方法喚醒,而是對等待線程進(jìn)行中斷,則會拋出InterruptedException異常信息。

3.3、通知

調(diào)用Condition的signal()方法,將會喚醒在等待隊(duì)列中等待最長時(shí)間的節(jié)點(diǎn)(條件隊(duì)列里的首節(jié)點(diǎn)),在喚醒節(jié)點(diǎn)前,會將節(jié)點(diǎn)移到同步隊(duì)列中。當(dāng)前線程加入到等待隊(duì)列中如圖所示:

詳解Java并發(fā)之Condition

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

詳解Java并發(fā)之Condition

被喚醒的線程將從await方法中的while循環(huán)中退出。隨后加入到同步狀態(tài)的競爭當(dāng)中去。成功獲取到競爭的線程則會返回到await方法之前的狀態(tài)。

四、總結(jié)

調(diào)用await方法后,將當(dāng)前線程加入Condition等待隊(duì)列中。當(dāng)前線程釋放鎖。否則別的線程就無法拿到鎖而發(fā)生死鎖。自旋(while)掛起,不斷檢測節(jié)點(diǎn)是否在同步隊(duì)列中了,如果是則嘗試獲取鎖,否則掛起。當(dāng)線程被signal方法喚醒,被喚醒的線程將從await()方法中的while循環(huán)中退出來,然后調(diào)用acquireQueued()方法競爭同步狀態(tài)。

五、利用Condition實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模式

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(); } } /** * 消費(fèi)者 * @return * @throws InterruptedException */ public Object get() throws InterruptedException { Object obj; lock.lock(); try { while (buffer.size() == 0){ //隊(duì)列中沒有數(shù)據(jù)了 線程進(jìn)入等待狀態(tài)fullCondition.await(); } obj = buffer.poll(); notFullCondition.signal(); //通知 } finally { lock.unlock(); } return obj; }}

以上就是詳解Java并發(fā)之Condition的詳細(xì)內(nèi)容,更多關(guān)于Java并發(fā)Condition的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 新营市| 七台河市| 南部县| 阳东县| 平凉市| 镇雄县| 三门峡市| 泽普县| 龙口市| 绵竹市| 财经| 特克斯县| 泰和县| 巨鹿县| 滦南县| 凤冈县| 钦州市| 高清| 从化市| 安吉县| 班戈县| 丽水市| 大足县| 林西县| 阜宁县| 宜君县| 黔东| 南投县| 静安区| 铅山县| 南召县| 内黄县| 长沙县| 扎鲁特旗| 凤山市| 翁源县| 时尚| 根河市| 南宁市| 九台市| 凤冈县|