Condition 原理解析
生活随笔
收集整理的這篇文章主要介紹了
Condition 原理解析
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
流程
當(dāng)調(diào)用wait 方法的時(shí)候從拿到一個(gè)最新創(chuàng)建的Node并加入 Condition 隊(duì)列
喚醒AQS隊(duì)列中的一個(gè)線程
判斷node是否在aqs 隊(duì)列上
如果不在的話將當(dāng)前線程阻塞
當(dāng)調(diào)用signal方法的時(shí)候會(huì)喚醒指定的線程 并添加當(dāng)前節(jié)點(diǎn)到AQS隊(duì)列
wait()
public final void await() throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();//添加一個(gè)節(jié)點(diǎn)到Condition 隊(duì)列中 如果沒有則創(chuàng)建放到尾節(jié)點(diǎn) 尾插法 節(jié)點(diǎn)狀態(tài)為 condtitionNode node = addConditionWaiter();//釋放當(dāng)前的鎖 得到鎖的狀態(tài) 并喚醒處于 aqs隊(duì)列的一個(gè)線程long savedState = fullyRelease(node);int interruptMode = 0;//判斷一個(gè)節(jié)點(diǎn)是否在aqs隊(duì)列上while (!isOnSyncQueue(node)) {//如果在 park自己阻塞等待LockSupport.park(this);//判斷自己是否被中斷if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;}//嘗試獲取鎖if (acquireQueued(node, savedState) && interruptMode != THROW_IE)interruptMode = REINTERRUPT;//如果node 的下一個(gè)節(jié)點(diǎn)不是null 清理condition隊(duì)列上的節(jié)點(diǎn)if (node.nextWaiter != null) // clean up if cancelledunlinkCancelledWaiters();if (interruptMode != 0)//線程中斷拋異常reportInterruptAfterWait(interruptMode);}創(chuàng)建Node 節(jié)點(diǎn)并加入Condition隊(duì)列中(單向鏈表)
如果node 是空則創(chuàng)建一個(gè)新的node狀態(tài)為 CONDITION并設(shè)置成尾節(jié)點(diǎn)
如果不是空并且節(jié)點(diǎn)狀態(tài)不是 CONDITION 則從鏈表中刪除 然后直接返回尾節(jié)點(diǎn)
如果不是空節(jié)點(diǎn)并且節(jié)點(diǎn)狀態(tài)是 CONDITION 則把尾節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)設(shè)置成剛構(gòu)建好的節(jié)點(diǎn)
刪除不是CONDITION狀態(tài)的節(jié)點(diǎn)
private void unlinkCancelledWaiters() {Node t = firstWaiter;Node trail = null;// 如果首節(jié)點(diǎn)不為空while (t != null) {// 獲取到下個(gè)節(jié)點(diǎn)Node next = t.nextWaiter;// 如果該節(jié)點(diǎn)的狀態(tài)不等于conditon,則該節(jié)點(diǎn)需要在鏈表中刪除if (t.waitStatus != Node.CONDITION) {// 該節(jié)點(diǎn)的下個(gè)節(jié)點(diǎn)設(shè)置為空,意味著垃圾回收后就回收該節(jié)點(diǎn)t.nextWaiter = null;// trail 為空,則把下一個(gè)節(jié)點(diǎn)負(fù)責(zé)給首節(jié)點(diǎn)if (trail == null)firstWaiter = next;else// 把下一個(gè)節(jié)點(diǎn)賦值給next,這樣鏈表就要繼續(xù)連接起來(lái)trail.nextWaiter = next;if (next == null)lastWaiter = trail;}// 等于condtion,把該節(jié)點(diǎn)賦值給尾節(jié)點(diǎn)elsetrail = t;// 下個(gè)一個(gè)節(jié)點(diǎn)賦值給t,進(jìn)行下一次循環(huán)t = next;}}喚醒AQS隊(duì)列中的一個(gè)線程
final long fullyRelease(Node node) {boolean failed = true;try {//拿當(dāng)前鎖的狀態(tài)值long savedState = getState();//釋放鎖if (release(savedState)) {failed = false;return savedState;} else {throw new IllegalMonitorStateException();}} finally {if (failed)node.waitStatus = Node.CANCELLED;}} protected final boolean tryRelease(int releases) {//state -1int c = getState() - releases;if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;if (c == 0) {//如果c =0 表示當(dāng)前是無(wú)鎖狀態(tài) 把線程iq清空free = true;setExclusiveOwnerThread(null);}//重新設(shè)置 statesetState(c);return free;} private void unparkSuccessor(Node node) {/** If status is negative (i.e., possibly needing signal) try* to clear in anticipation of signalling. It is OK if this* fails or if status is changed by waiting thread.*/int ws = node.waitStatus;if (ws < 0)//設(shè)置head節(jié)點(diǎn)的狀態(tài)為0 compareAndSetWaitStatus(node, ws, 0);/** Thread to unpark is held in successor, which is normally* just the next node. But if cancelled or apparently null,* traverse backwards from tail to find the actual* non-cancelled successor.*///拿到head節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)Node s = node.next;//如果下一個(gè)節(jié)點(diǎn)為null 或者 status>0則表示是 CANCELLED 狀態(tài)//聽過(guò)尾部節(jié)點(diǎn)開始掃描 找到距離 head最近的一個(gè) waitStatus<=0的節(jié)點(diǎn)if (s == null || s.waitStatus > 0) {s = null;for (Node t = tail; t != null && t != node; t = t.prev)if (t.waitStatus <= 0)s = t;}//如果next 節(jié)點(diǎn)不等于空直接喚醒這個(gè)線程if (s != null)LockSupport.unpark(s.thread);}判斷當(dāng)前節(jié)點(diǎn)是否在同步隊(duì)列中,返回 false 表示不在,返回true 表示如果不在,將當(dāng)前線程掛起
final boolean isOnSyncQueue(Node node) {// 如果狀態(tài)是condition,證明一定不再同步隊(duì)列里,condition狀態(tài)只存在于等待隊(duì)列,在同步隊(duì)列里,node.prev是一定不為空的,因?yàn)橛袀€(gè)head的節(jié)點(diǎn)if (node.waitStatus == Node.CONDITION || node.prev == null)return false;// 在等待隊(duì)列里,node.next 是等于空的,不等于空就是在同步隊(duì)列當(dāng)中if (node.next != null) // If has successor, it must be on queuereturn true;// 遍歷正個(gè)同步隊(duì)列,判斷node是否在同步隊(duì)列當(dāng)中return findNodeFromTail(node);}比如由于線程A調(diào)用了await 方法然后進(jìn)入阻塞狀態(tài)并喚醒了處于aqs 隊(duì)列中的線程B此時(shí)線程B執(zhí)行調(diào)用 signal 會(huì)喚醒處于 Condition 隊(duì)列中阻塞等待的節(jié)點(diǎn)signal
public final void signal() {// 判斷當(dāng)前線程是否獲取到了鎖,如果沒有拋異常if (!isHeldExclusively())throw new IllegalMonitorStateException();Node first = firstWaiter;// 如果首節(jié)點(diǎn)不為空,喚醒首節(jié)點(diǎn)if (first != null)doSignal(first);}doSignal
private void doSignal(Node first) {do {// frist的下一個(gè)節(jié)點(diǎn)如果為空,就把lastWaiter設(shè)置為空if ( (firstWaiter = first.nextWaiter) == null)lastWaiter = null;// 不為空,再把first 節(jié)點(diǎn)從等待隊(duì)列中移除first.nextWaiter = null;} while (!transferForSignal(first) &&// 返回false,firstWaiter已經(jīng)被從新賦值過(guò)了,如果不是空,進(jìn)行下一次遍歷(first = firstWaiter) != null);}transferForSignal
final boolean transferForSignal(Node node) {// 如果該節(jié)點(diǎn)不是condition狀態(tài)(可能編程了cancelled狀態(tài)),waitStatus=0,就會(huì)設(shè)置失敗,返回falseif (!compareAndSetWaitStatus(node, Node.CONDITION, 0))return false;// 將該節(jié)點(diǎn)放入到AQS隊(duì)列中Node p = enq(node);int ws = p.waitStatus;// 如果上一個(gè)節(jié)點(diǎn)狀態(tài)沒有被改變,也就是沒有編程cancelled狀態(tài),就將該節(jié)點(diǎn)狀態(tài)設(shè)置成singal狀態(tài)if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))// 如果狀態(tài)已經(jīng)是cancelled狀態(tài),將該節(jié)點(diǎn)的線程掛起LockSupport.unpark(node.thread);return true;}總結(jié)
以上是生活随笔為你收集整理的Condition 原理解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php(thinkphp)在linux系
- 下一篇: Favorite Setting