日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java Condition类的详细介绍

發(fā)布時(shí)間:2024/1/18 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java Condition类的详细介绍 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一 、condition 介紹及demo

 Condition是在java 1.5中才出現(xiàn)的,它用來(lái)替代傳統(tǒng)的Object的wait()、notify()實(shí)現(xiàn)線程間的協(xié)作,相比使用Object的wait()、notify(),使用Condition的await()、signal()這種方式實(shí)現(xiàn)線程間協(xié)作更加安全和高效。因此通常來(lái)說(shuō)比較推薦使用Condition,阻塞隊(duì)列實(shí)際上是使用了Condition來(lái)模擬線程間協(xié)作。

  • Condition是個(gè)接口,基本的方法就是await()和signal()方法;
  • Condition依賴于Lock接口,生成一個(gè)Condition的基本代碼是lock.newCondition()?
  • ?調(diào)用Condition的await()和signal()方法,都必須在lock保護(hù)之內(nèi),就是說(shuō)必須在lock.lock()和lock.unlock之間才可以使用

  Conditon中的await()對(duì)應(yīng)Object的wait();

  Condition中的signal()對(duì)應(yīng)Object的notify();

? ? ? ?Condition中的signalAll()對(duì)應(yīng)Object的notifyAll()

?condition常見(jiàn)例子arrayblockingqueue。下面是demo: 

public class ConTest {final Lock lock = new ReentrantLock();final Condition condition = lock.newCondition();public static void main(String[] args) {// TODO Auto-generated method stubConTest test = new ConTest();Producer producer = test.new Producer();Consumer consumer = test.new Consumer();consumer.start(); producer.start();}class Consumer extends Thread{@Overridepublic void run() {consume();}private void consume() {try {lock.lock();System.out.println("我在等一個(gè)新信號(hào)"+this.currentThread().getName());condition.await();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally{System.out.println("拿到一個(gè)信號(hào)"+this.currentThread().getName());lock.unlock();}}}class Producer extends Thread{@Overridepublic void run() {produce();}private void produce() { try {lock.lock();System.out.println("我拿到鎖"+this.currentThread().getName());condition.signalAll();System.out.println("我發(fā)出了一個(gè)信號(hào):"+this.currentThread().getName());} finally{lock.unlock();}}}}

運(yùn)行結(jié)果:

我在等一個(gè)新信號(hào)Thread-1
我拿到鎖Thread-0
我發(fā)出了一個(gè)信號(hào):Thread-0
拿到一個(gè)信號(hào)Thread-1

Condition的執(zhí)行方式,是當(dāng)前線程在Consumer中調(diào)用await方法后,線程Consumer將釋放鎖,并且將自己沉睡,等待喚醒,線程Producer獲取到鎖后,開(kāi)始做事,完畢后,調(diào)用Condition的signalall方法,喚醒線程Consumer,線程Consumer恢復(fù)執(zhí)行。

以上說(shuō)明Condition是一個(gè)多線程間協(xié)調(diào)通信的工具類,使得某個(gè),或者某些線程一起等待某個(gè)條件(Condition),只有當(dāng)該條件具備( signal 或者 signalAll方法被帶調(diào)用)時(shí) ,這些等待線程才會(huì)被喚醒,從而重新?tīng)?zhēng)奪鎖。

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

public class ConTest2 {private int queueSize = 10;private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);private Lock lock = new ReentrantLock();private Condition notFull = lock.newCondition();private Condition notEmpty = lock.newCondition();public static void main(String[] args) throws InterruptedException {ConTest2 test = new ConTest2();Producer producer = test.new Producer();Consumer consumer = test.new Consumer();producer.start();consumer.start();Thread.sleep(0);producer.interrupt();consumer.interrupt();}class Consumer extends Thread{@Overridepublic void run() {consume();}volatile boolean flag=true;private void consume() {while(flag){lock.lock();try {if(queue.isEmpty()){try {System.out.println("隊(duì)列空,等待數(shù)據(jù)");notEmpty.await();} catch (InterruptedException e) {flag =false;}}queue.poll(); //每次移走隊(duì)首元素notFull.signal();System.out.println("從隊(duì)列取走一個(gè)元素,隊(duì)列剩余"+queue.size()+"個(gè)元素");} finally{lock.unlock();}}}}class Producer extends Thread{@Overridepublic void run() {produce();}volatile boolean flag=true;private void produce() {while(flag){lock.lock();try {if(queue.size() == queueSize){try {System.out.println("隊(duì)列滿,等待有空余空間");notFull.await();} catch (InterruptedException e) {flag =false;}}queue.offer(1); //每次插入一個(gè)元素notEmpty.signal();System.out.println("向隊(duì)列取中插入一個(gè)元素,隊(duì)列剩余空間:"+(queueSize-queue.size()));} finally{lock.unlock();}}}} }

運(yùn)行結(jié)果:?

向隊(duì)列取中插入一個(gè)元素,隊(duì)列剩余空間:9
向隊(duì)列取中插入一個(gè)元素,隊(duì)列剩余空間:8
向隊(duì)列取中插入一個(gè)元素,隊(duì)列剩余空間:7
向隊(duì)列取中插入一個(gè)元素,隊(duì)列剩余空間:6
向隊(duì)列取中插入一個(gè)元素,隊(duì)列剩余空間:5
向隊(duì)列取中插入一個(gè)元素,隊(duì)列剩余空間:4
向隊(duì)列取中插入一個(gè)元素,隊(duì)列剩余空間:3
向隊(duì)列取中插入一個(gè)元素,隊(duì)列剩余空間:2
向隊(duì)列取中插入一個(gè)元素,隊(duì)列剩余空間:1
向隊(duì)列取中插入一個(gè)元素,隊(duì)列剩余空間:0
隊(duì)列滿,等待有空余空間
向隊(duì)列取中插入一個(gè)元素,隊(duì)列剩余空間:-1
從隊(duì)列取走一個(gè)元素,隊(duì)列剩余10個(gè)元素
從隊(duì)列取走一個(gè)元素,隊(duì)列剩余9個(gè)元素
從隊(duì)列取走一個(gè)元素,隊(duì)列剩余8個(gè)元素
從隊(duì)列取走一個(gè)元素,隊(duì)列剩余7個(gè)元素
從隊(duì)列取走一個(gè)元素,隊(duì)列剩余6個(gè)元素
從隊(duì)列取走一個(gè)元素,隊(duì)列剩余5個(gè)元素
從隊(duì)列取走一個(gè)元素,隊(duì)列剩余4個(gè)元素
從隊(duì)列取走一個(gè)元素,隊(duì)列剩余3個(gè)元素
從隊(duì)列取走一個(gè)元素,隊(duì)列剩余2個(gè)元素
從隊(duì)列取走一個(gè)元素,隊(duì)列剩余1個(gè)元素
從隊(duì)列取走一個(gè)元素,隊(duì)列剩余0個(gè)元素
隊(duì)列空,等待數(shù)據(jù)
從隊(duì)列取走一個(gè)元素,隊(duì)列剩余0個(gè)元素


二 、Condition接口?

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

await() :造成當(dāng)前線程在接到信號(hào)或被中斷之前一直處于等待狀態(tài)。
await(long time, TimeUnit unit) :造成當(dāng)前線程在接到信號(hào)、被中斷或到達(dá)指定等待時(shí)間之前一直處于等待狀態(tài)
awaitNanos(long nanosTimeout) :造成當(dāng)前線程在接到信號(hào)、被中斷或到達(dá)指定等待時(shí)間之前一直處于等待狀態(tài)。返回值表示剩余時(shí)間,如果在nanosTimesout之前喚醒,那么返回值 = nanosTimeout - 消耗時(shí)間,如果返回值 <= 0 ,則可以認(rèn)定它已經(jīng)超時(shí)了。
awaitUninterruptibly() :造成當(dāng)前線程在接到信號(hào)之前一直處于等待狀態(tài)。【注意:該方法對(duì)中斷不敏感】。
awaitUntil(Date deadline) :造成當(dāng)前線程在接到信號(hào)、被中斷或到達(dá)指定最后期限之前一直處于等待狀態(tài)。如果沒(méi)有到指定時(shí)間就被通知,則返回true,否則表示到了指定時(shí)間,返回返回false。
signal() :喚醒一個(gè)等待線程。該線程從等待方法返回前必須獲得與Condition相關(guān)的鎖。
signal()All :喚醒所有等待線程。能夠從等待方法返回的線程必須獲得與Condition相關(guān)的鎖。


三 condition實(shí)現(xiàn)分析:?

?

?

  • Condition接口包含了多種await方式和兩個(gè)通知方法
  • ConditionObject實(shí)現(xiàn)了Condition接口,是AbstractQueuedSynchronizer的內(nèi)部類(因?yàn)镃ondition的操作都需要獲取想關(guān)聯(lián)的鎖)
  • Reentrantlock的newCondition方法返回與某個(gè)lock實(shí)例相關(guān)的Condition對(duì)象

結(jié)合上面的類圖,我們看到condition實(shí)現(xiàn)是依賴于aqs,而aqs是個(gè)抽象類。里面定義了同步器的基本框架,實(shí)現(xiàn)了基本的結(jié)構(gòu)功能。只留有狀態(tài)條件的維護(hù)由具體同步器根據(jù)具體場(chǎng)景來(lái)定制,如常見(jiàn)的 ReentrantLock 、 RetrantReadWriteLock和CountDownLatch 等等,
?

等待隊(duì)列

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

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

public class ConditionObject implements Condition, java.io.Serializable {private static final long serialVersionUID = 1173984872572414699L;/** First node of condition queue. */private transient Node firstWaiter;/** Last node of condition queue. */private transient Node lastWaiter;

等待

? ?當(dāng)線程調(diào)用了Condition的await()方法以后。線程就作為隊(duì)列中的一個(gè)節(jié)點(diǎn)被加入到等待隊(duì)列中去了。同時(shí)會(huì)釋放鎖的擁有。當(dāng)從await方法返回的時(shí)候。當(dāng)前線程一定會(huì)獲取condition相關(guān)聯(lián)的鎖。

? ?如果從隊(duì)列(同步隊(duì)列和等待隊(duì)列)的角度去看await()方法,當(dāng)調(diào)用await()方法時(shí),相當(dāng)于同步隊(duì)列的首節(jié)點(diǎn)(獲取鎖的節(jié)點(diǎn))移動(dòng)到Condition的等待隊(duì)列中。

? 調(diào)用該方法的線程成功的獲取鎖的線程,也就是同步隊(duì)列的首節(jié)點(diǎn),該方法會(huì)將當(dāng)前線程構(gòu)造成節(jié)點(diǎn)并加入到等待隊(duì)列中,然后釋放同步狀態(tài),喚醒同步隊(duì)列中的后繼節(jié)點(diǎn),然后當(dāng)前線程會(huì)進(jìn)入等待狀態(tài)。

? ? 當(dāng)?shù)却?duì)列中的節(jié)點(diǎn)被喚醒的時(shí)候,則喚醒節(jié)點(diǎn)的線程開(kāi)始嘗試獲取同步狀態(tài)。如果不是通過(guò) 其他線程調(diào)用Condition.signal()方法喚醒,而是對(duì)等待線程進(jìn)行中斷,則會(huì)拋出InterruptedException異常信息。

?我們看一下這個(gè)await的方法

public final void await() throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();Node node = addConditionWaiter(); //將當(dāng)前線程包裝下后,添加到Condition自己維護(hù)的一個(gè)鏈表中int savedState = fullyRelease(node); //釋放當(dāng)前線程占有的鎖,從demo中看到,調(diào)用await前,當(dāng)前線程是占有鎖的int interruptMode = 0;//釋放完畢后,遍歷AQS的隊(duì)列,看當(dāng)前節(jié)點(diǎn)是否在隊(duì)列中,//不在 說(shuō)明它還沒(méi)有競(jìng)爭(zhēng)鎖的資格,所以繼續(xù)將自己沉睡。//直到它被加入到隊(duì)列中,聰明的你可能猜到了,//沒(méi)有錯(cuò),在singal的時(shí)候加入不就可以了?while (!isOnSyncQueue(node)) {LockSupport.park(this);if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;}//被喚醒后,重新開(kāi)始正式競(jìng)爭(zhēng)鎖,同樣,如果競(jìng)爭(zhēng)不到還是會(huì)將自己沉睡,等待喚醒重新開(kāi)始競(jìng)爭(zhēng)if (acquireQueued(node, savedState) && interruptMode != THROW_IE)interruptMode = REINTERRUPT;if (node.nextWaiter != null) // clean up if cancelledunlinkCancelledWaiters();if (interruptMode != 0)reportInterruptAfterWait(interruptMode); }

?結(jié)合代碼去看,同步隊(duì)列的首節(jié)點(diǎn) 并不會(huì)直接加入等待隊(duì)列,而是通過(guò)addConditionWaiter把當(dāng)前線程構(gòu)造成一個(gè)新節(jié)點(diǎn)并加入到等待隊(duì)列中。

private Node addConditionWaiter() {Node t = lastWaiter;// If lastWaiter is cancelled, clean out.if (t != null && t.waitStatus != Node.CONDITION) {unlinkCancelledWaiters();t = lastWaiter;}Node node = new Node(Thread.currentThread(), Node.CONDITION);if (t == null)firstWaiter = node;elset.nextWaiter = node;lastWaiter = node;return node; }

通知

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

?回到上面的demo,鎖被釋放后,線程Consumer開(kāi)始沉睡,這個(gè)時(shí)候線程因?yàn)榫€程Consumer沉睡時(shí),會(huì)喚醒AQS隊(duì)列中的頭結(jié)點(diǎn),所所以線程Producer會(huì)開(kāi)始競(jìng)爭(zhēng)鎖,并獲取到,執(zhí)行完后線程Producer會(huì)調(diào)用signal方法,“發(fā)出”signal信號(hào),signal方法如下:

public final void signal() {if (!isHeldExclusively())throw new IllegalMonitorStateException();Node first = firstWaiter; //firstWaiter為condition自己維護(hù)的一個(gè)鏈表的頭結(jié)點(diǎn),取出第一個(gè)節(jié)點(diǎn)后開(kāi)始喚醒操作if (first != null)doSignal(first); }

? ? ? ?在調(diào)用signal()方法之前必須先判斷是否獲取到了鎖(isHeldExclusively方法)。接著獲取等待隊(duì)列的首節(jié)點(diǎn),將其移動(dòng)到同步隊(duì)列并且利用LockSupport喚醒節(jié)點(diǎn)中的線程。
? ? ? 被喚醒的線程將從await方法中的while循環(huán)中退出( ?while (!isOnSyncQueue(node)) { 方法返回true,節(jié)點(diǎn)已經(jīng)在同步隊(duì)列中)。隨后調(diào)用同步器的acquireQueued()方法加入到同步狀態(tài)的競(jìng)爭(zhēng)當(dāng)中去。成功獲取到競(jìng)爭(zhēng)的線程從先前調(diào)用await方法返回,此時(shí)該線程已經(jīng)成功獲取了鎖。


AQS的同步隊(duì)列與Condition的等待隊(duì)列,兩個(gè)隊(duì)列的作用是不同,事實(shí)上,每個(gè)線程也僅僅會(huì)同時(shí)存在以上兩個(gè)隊(duì)列中的一個(gè),流程是這樣的:

可以這樣理解,整個(gè)協(xié)作過(guò)程是靠結(jié)點(diǎn)在AQS的等待隊(duì)列和Condition的等待隊(duì)列中來(lái)回移動(dòng)實(shí)現(xiàn)的,每個(gè)隊(duì)列的意義不同,Condition作為一個(gè)條件類,很好的自己維護(hù)了一個(gè)等待信號(hào)的隊(duì)列,并在適時(shí)的時(shí)候?qū)⒔Y(jié)點(diǎn)加入到AQS的等待隊(duì)列中來(lái)實(shí)現(xiàn)的喚醒操作

總結(jié)

以上是生活随笔為你收集整理的java Condition类的详细介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 一区二区三区伦理片 | 内谢少妇xxxxx8老少交视频 | 国产精品va无码一区二区 | 国产一区二区免费视频 | 国产精品我不卡 | 农村脱精光一级 | 欧美精品小视频 | www.国产免费 | 国产精品伦理一区二区 | 国产又粗又猛又黄 | 欧美日韩综合一区二区 | 欧美经典一区二区 | 日本男男激情gay办公室 | 免费国产黄色 | 韩国电影大尺度在线观看 | 亚州视频在线 | 欧美a一级 | 成人看片免费 | 黄色一级片欧美 | 九九久久视频 | 亚洲 欧美 另类 综合 偷拍 | 最新国产露脸在线观看 | 可以免费看av | 偷偷操不一样的久久 | 国产视频麻豆 | 久久黄色免费网站 | 国产日产久久高清欧美一区 | 亚洲无限码 | 亚洲欧洲无码一区二区三区 | 欧美性猛交xxxx乱大交退制版 | 精品国产乱码久久久久久鸭王1 | 国产强伦人妻毛片 | 亚洲精品123区 | 国产乱淫精品一区二区三区毛片 | 欧美二区在线观看 | 在线一级片 | 色宗合| 亚洲一区二区视频 | 草久影院 | 久草久 | 亚洲黄色免费观看 | 亚洲日本三级 | 亚洲激情短视频 | 九九综合九九综合 | 波多野结衣国产在线 | 午夜三级在线观看 | 日本亲近相奷中文字幕 | 午夜影院男女 | 亚洲精品高清无码视频 | 色呦| 成人动漫视频在线观看 | 人妻丝袜一区二区三区 | 国产精品久久久久久久久久久久 | 国产精品久久午夜夜伦鲁鲁 | 手机在线免费看av | 精品在线观看一区 | 天天干天天操天天碰 | 无码人妻精品一区二区三区99不卡 | 午夜网站在线观看 | 欧美黄色一级网站 | 51精品国产人成在线观看 | 日本免费不卡一区二区 | 各处沟厕大尺度偷拍女厕嘘嘘 | 欧美理论片在线观看 | 99这里只有精品视频 | 人成在线免费视频 | 青娱乐超碰 | 国产男人搡女人免费视频 | www.狠狠艹 | xxxx色| 成年人在线免费看 | 久久天天东北熟女毛茸茸 | 免费看av软件| 大吊一区二区三区 | 久久久久久综合网 | 亚洲美女激情视频 | 丁香六月啪啪 | 中国黄色1级片 | 国产精品久久久久毛片大屁完整版 | 国产精品网页 | 黄色一机片| 男操女视频在线观看 | av在线电影院 | 豆花免费跳转入口官网 | 五月激情在线 | 亚洲永久无码精品一区二区 | 欧美不卡一区二区三区 | 在线色站| 黄色片免费在线播放 | 亚洲精品在线播放视频 | 亚洲一片| 国产人妻精品一区二区三 | 色干综合 | 超碰中文字幕 | 日本色综合网 | www.天天色| bt天堂av | 樱桃国产成人精品视频 | 日韩福利在线播放 |