电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

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

解析java中的condition

瀏覽:89日期:2022-08-10 17:55:57
目錄一、condition 介紹及demo二、Condition接口     三、condition實現(xiàn)分析3.1、等待隊列3.2、等待3.3、通知一、condition 介紹及demo

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

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

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

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

Condition中的signalAll()對應(yīng)Object的notifyAll()。

解析java中的condition

condition常見例子arrayblockingqueue。下面是demo:

package thread; import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;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('我在等一個新信號'+this.currentThread().getName()); condition.await(); } catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally{System.out.println('拿到一個信號'+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ā)出了一個信號:'+this.currentThread().getName());} finally{ lock.unlock();} } } }

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

解析java中的condition

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

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

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

package thread;import java.util.PriorityQueue;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;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 { while(queue.isEmpty()){try { System.out.println('隊列空,等待數(shù)據(jù)'); notEmpty.await();} catch (InterruptedException e) { flag =false;} } queue.poll();//每次移走隊首元素 notFull.signal(); System.out.println('從隊列取走一個元素,隊列剩余'+queue.size()+'個元素');} finally{ lock.unlock();} }} } class Producer extends Thread{ @Overridepublic void run() { produce();}volatile boolean flag=true; private void produce() { while(flag){lock.lock();try { while(queue.size() == queueSize){try { System.out.println('隊列滿,等待有空余空間'); notFull.await();} catch (InterruptedException e) { flag =false;} } queue.offer(1);//每次插入一個元素 notEmpty.signal(); System.out.println('向隊列取中插入一個元素,隊列剩余空間:'+(queueSize-queue.size()));} finally{ lock.unlock();} }} }}

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

解析java中的condition

二、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實現(xiàn)分析

解析java中的condition

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

public abstract class AbstractQueuedLongSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {

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

3.1、等待隊列

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

解析java中的condition

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

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;3.2、等待

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

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

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

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

   解析java中的condition

我們看一下這個await的方法,它是AQS的方法,

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

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

/** * Adds a new waiter to wait queue. * @return its new wait node */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;}3.3、通知

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

解析java中的condition

回到上面的demo,鎖被釋放后,線程Consumer開始沉睡,這個時候線程因為線程Consumer沉睡時,會喚醒AQS隊列中的頭結(jié)點,所所以線程Producer會開始競爭鎖,并獲取到,執(zhí)行完后線程Producer會調(diào)用signal方法,“發(fā)出”signal信號,signal方法如下:

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

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

被喚醒的線程將從await方法中的while循環(huán)中退出(  while (!isOnSyncQueue(node)) { 方法返回true,節(jié)點已經(jīng)在同步隊列中)。隨后調(diào)用同步器的acquireQueued()方法加入到同步狀態(tài)的競爭當(dāng)中去。成功獲取到競爭的線程從先前調(diào)用await方法返回,此時該線程已經(jīng)成功獲取了鎖。

*********************************************

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

解析java中的condition

注意:

1.線程producer調(diào)用signal方法,這個時候Condition的等待隊列中只有線程Consumer一個節(jié)點,于是它被取出來,并被加入到AQS的等待隊列中。  注意,這個時候,線程Consumer 并沒有被喚醒。

2.Sync是AQS的抽象子類,實現(xiàn)可重入和互斥的大部分功能。在Sync的子類中有FairSync和NonfairSync兩種代表公平鎖策略和非公平鎖策略。Sync lock方法留給子類去實現(xiàn),NonfairSync的實現(xiàn):

final void lock() { if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread()); elseacquire(1);}

其中如果一開始獲取鎖成功,是直接設(shè)置當(dāng)前線程。

否則執(zhí)行acquire(1),也就是進(jìn)入aqs等待隊列。這里不展開細(xì)節(jié)。

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

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

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 蒸汽热收缩机_蒸汽发生器_塑封机_包膜机_封切收缩机_热收缩包装机_真空机_全自动打包机_捆扎机_封箱机-东莞市中堡智能科技有限公司 | 玉米深加工机械,玉米加工设备,玉米加工机械等玉米深加工设备制造商-河南成立粮油机械有限公司 | 24位ADC|8位MCU-芯易德科技有限公司| 杭州营业执照代办-公司变更价格-许可证办理流程_杭州福道财务管理咨询有限公司 | 大型冰雕-景区冰雕展制作公司,3D创意设计源头厂家-[赛北冰雕] | YT保温材料_YT无机保温砂浆_外墙保温材料_南阳银通节能建材高新技术开发有限公司 | 细胞染色-流式双标-试剂盒免费代做-上海研谨生物科技有限公司 | 德国GMN轴承,GMN角接触球轴承,GMN单向轴承,GMN油封,GMN非接触式密封 | 食药成分检测_调料配方还原_洗涤剂化学成分分析_饲料_百检信息科技有限公司 | 购买舔盐、舔砖、矿物质盐压块机,鱼饵、鱼饲料压块机--请到杜甫机械 | 上海公司注册-代理记账-招投标审计-上海昆仑扇财税咨询有限公司 上海冠顶工业设备有限公司-隧道炉,烘箱,UV固化机,涂装设备,高温炉,工业机器人生产厂家 | 热处理炉-退火炉-回火炉设备厂家-丹阳市电炉厂有限公司 | 酒精检测棒,数显温湿度计,酒安酒精测试仪,酒精检测仪,呼气式酒精检测仪-郑州欧诺仪器有限公司 | 生物制药洁净车间-GMP车间净化工程-食品净化厂房-杭州波涛净化设备工程有限公司 | 步入式高低温测试箱|海向仪器 | 玻璃钢型材_拉挤模具_玻璃钢拉挤设备——滑县康百思 | 水上浮桥-游艇码头-浮动码头-游船码头-码瑞纳游艇码头工程 | 考勤系统_考勤管理系统_网络考勤软件_政企|集团|工厂复杂考勤工时统计排班管理系统_天时考勤 | 机械加工_绞车配件_立式离心机_减速机-洛阳三永机械厂 | 沈阳激光机-沈阳喷码机-沈阳光纤激光打标机-沈阳co2激光打标机 | 金属抛光机-磁悬浮抛光机-磁力研磨机-磁力清洗机 - 苏州冠古科技 | 卫浴散热器,卫浴暖气片,卫生间背篓暖气片,华圣格浴室暖气片 | 国际学校_国际学校哪个好_国际课程学校-国际学校择校网 | 工装定制/做厂家/公司_工装订做/制价格/费用-北京圣达信工装 | 一级建造师培训_一建培训机构_中建云筑建造师培训网校 | 奶茶加盟,奶茶加盟店连锁品牌-甜啦啦官网 | 起好名字_取个好名字_好名网免费取好名在线打分 | 热熔胶网膜|pes热熔网膜价格|eva热熔胶膜|热熔胶膜|tpu热熔胶膜厂家-苏州惠洋胶粘制品有限公司 | 彭世修脚_修脚加盟_彭世修脚加盟_彭世足疗加盟_足疗加盟连锁_彭世修脚技术培训_彭世足疗 | 暴风影音| 中山市派格家具有限公司【官网】 | 继电器模组-IO端子台-plc连接线-省配线模组厂家-世麦德 | 杭州ROHS检测仪-XRF测试仪价格-百科 | 室内室外厚型|超薄型|非膨胀型钢结构防火涂料_隧道专用防火涂料厂家|电话|价格|批发|施工 | 主题班会网 - 安全教育主题班会,各类主题班会PPT模板 | 吉祥新世纪铝塑板_生产铝塑板厂家_铝塑板生产厂家_临沂市兴达铝塑装饰材料有限公司 | 120kv/2mA直流高压发生器-60kv/2mA-30kva/50kv工频耐压试验装置-旭明电工 | 仓储笼_金属箱租赁_循环包装_铁网箱_蝴蝶笼租赁_酷龙仓储笼租赁 测试治具|过炉治具|过锡炉治具|工装夹具|测试夹具|允睿自动化设备 | 丽陂特官网_手机信号屏蔽器_Wifi信号干扰器厂家_学校考场工厂会议室屏蔽仪 | 京马网,京马建站,网站定制,营销型网站建设,东莞建站,东莞网站建设-首页-京马网 | 沈阳真空机_沈阳真空包装机_沈阳大米真空包装机-沈阳海鹞真空包装机械有限公司 |