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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

java并发condition_Java并发之Condition的实现分析

發(fā)布時間:2024/9/27 java 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java并发condition_Java并发之Condition的实现分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、Condition的概念

介紹

回憶 synchronized 關(guān)鍵字,它配合 Object 的 wait()、notify() 系列方法可以實現(xiàn)等待/通知模式。

對于 Lock,通過 Condition 也可以實現(xiàn)等待/通知模式。

Condition 是一個接口。

Condition 接口的實現(xiàn)類是 Lock(AQS)中的 ConditionObject。

Lock 接口中有個 newCondition() 方法,通過這個方法可以獲得 Condition 對象(其實就是 ConditionObject)。

因此,通過 Lock 對象可以獲得 Condition 對象。

Lock lock = new ReentrantLock();Condition c1 = lock.newCondition();Condition c2 = lock.newCondition();

二、Condition的實現(xiàn)分析

實現(xiàn)

ConditionObject 類是 AQS 的內(nèi)部類,實現(xiàn)了 Condition 接口。

public class ConditionObject implements Condition, java.io.Serializable { private transient Node firstWaiter; private transient Node lastWaiter; ...

可以看到,等待隊列和同步隊列一樣,使用的都是同步器 AQS 中的節(jié)點類 Node。

同樣擁有首節(jié)點和尾節(jié)點,

每個 Condition 對象都包含著一個 FIFO 隊列。

結(jié)構(gòu)圖:

Java并發(fā)之Condition的實現(xiàn)分析-1.jpg (9.01 KB, 下載次數(shù): 0)

2020-6-7 22:32 上傳

等待

調(diào)用 Condition 的 await() 方法會使線程進(jìn)入等待隊列,并釋放鎖,線程狀態(tài)變?yōu)榈却隣顟B(tài)。

public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); //釋放同步狀態(tài)(鎖) int savedState = fullyRelease(node); int interruptMode = 0; //判斷節(jié)點是否放入同步對列 while (!isOnSyncQueue(node)) { //阻塞 LockSupport.park(this); //如果已經(jīng)中斷了,則退出 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode);}

分析上述方法的大概過程:

將當(dāng)前線程創(chuàng)建為節(jié)點,加入等待隊列;釋放鎖,喚醒同步隊列中的后繼節(jié)點;while循環(huán)判斷節(jié)點是否放入同步隊列:

沒有放入,則阻塞,繼續(xù) while 循環(huán)(如果已經(jīng)中斷了,則退出)放入,則退出 while 循環(huán),執(zhí)行后面的判斷退出 while 說明節(jié)點已經(jīng)在同步隊列中,調(diào)用 acquireQueued() 方法加入同步狀態(tài)競爭。競爭到鎖后從 await() 方法返回,即退出該方法。

Java并發(fā)之Condition的實現(xiàn)分析-2.jpg (30.35 KB, 下載次數(shù): 0)

2020-6-7 22:32 上傳

addConditionWaiter() 方法:

private Node addConditionWaiter() { Node t = lastWaiter; if (t != null && t.waitStatus != Node.CONDITION) { //清除條件隊列中所有狀態(tài)不為Condition的節(jié)點 unlinkCancelledWaiters(); t = lastWaiter; } //將該線程創(chuàng)建節(jié)點,放入等待隊列 Node node = new Node(Thread.currentThread(), Node.CONDITION); if (t == null) firstWaiter = node; else t.nextWaiter = node; lastWaiter = node; return node;}

過程分析:同步隊列的首節(jié)點移動到等待隊列。加入尾節(jié)點之前會清除所有狀態(tài)不為 Condition 的節(jié)點。

通知

調(diào)用 Condition 的 signal() 方法,可以喚醒等待隊列的首節(jié)點(等待時間最長),喚醒之前會將該節(jié)點移動到同步隊列中。

public final void signal() { //判斷是否獲取了鎖 if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignal(first);}

過程:

先判斷當(dāng)前線程是否獲取了鎖;然后對首節(jié)點調(diào)用 doSignal() 方法。private void doSignal(Node first) { do { if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; } while (!transferForSignal(first) && (first = firstWaiter) != null);}

過程:

修改首節(jié)點;調(diào)用 transferForSignal() 方法將節(jié)點移動到同步隊列。final boolean transferForSignal(Node node) { //將節(jié)點狀態(tài)變?yōu)???if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; //將該節(jié)點加入同步隊列 Node p = enq(node); int ws = p.waitStatus; //如果結(jié)點p的狀態(tài)為cancel 或者修改waitStatus失敗,則直接喚醒 if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true;}

調(diào)用同步器的 enq 方法,將節(jié)點移動到同步隊列,

滿足條件后使用 LockSupport 喚醒該線程。

Java并發(fā)之Condition的實現(xiàn)分析-3.jpg (29.66 KB, 下載次數(shù): 0)

2020-6-7 22:32 上傳

當(dāng) Condition 調(diào)用 signalAll() 方法:

public final void signalAll() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignalAll(first);}private void doSignalAll(Node first) { lastWaiter = firstWaiter = null; do { Node next = first.nextWaiter; first.nextWaiter = null; transferForSignal(first); first = next; } while (first != null);}

可以看到 doSignalAll() 方法使用了 do-while 循環(huán)來喚醒每一個等待隊列中的節(jié)點,直到 first 為 null 時,停止循環(huán)。

一句話總結(jié) signalAll() 的作用:將等待隊列中的全部節(jié)點移動到同步隊列中,并喚醒每個節(jié)點的線程。

總結(jié)

整個過程可以分為三步:

第一步:一個線程獲取鎖后,通過調(diào)用 Condition 的 await() 方法,會將當(dāng)前線程先加入到等待隊列中,并釋放鎖。然后就在 await() 中的一個 while 循環(huán)中判斷節(jié)點是否已經(jīng)在同步隊列,是則嘗試獲取鎖,否則一直阻塞。

第二步:當(dāng)線程調(diào)用 signal() 方法后,程序首先檢查當(dāng)前線程是否獲取了鎖,然后通過 doSignal(Node first) 方法將節(jié)點移動到同步隊列,并喚醒節(jié)點中的線程。

第三步:被喚醒的線程,將從 await() 中的 while 循環(huán)中退出來,然后調(diào)用 acquireQueued() 方法競爭同步狀態(tài)。競爭成功則退出 await() 方法,繼續(xù)執(zhí)行。

總結(jié)

以上是生活随笔為你收集整理的java并发condition_Java并发之Condition的实现分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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