亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

CountDownLatch源碼解析之countDown()

2024-07-14 08:39:49
字體:
來源:轉載
供稿:網友

CountDownLatch 源碼解析—— countDown()

上一篇文章從源碼層面說了一下CountDownLatch 中 await() 的原理。這篇文章說一下countDown() 。

public void countDown() { //CountDownLatch sync.releaseShared(1);} ↓public final boolean releaseShared(int arg) { //AQS if (tryReleaseShared(arg)) {  doReleaseShared();  return true; } return false;} ↓protected boolean tryReleaseShared(int releases) { //CountDownLatch.Sync  // Decrement count; signal when transition to zero for (;;) {  int c = getState();  if (c == 0)   return false;  int nextc = c-1;  if (compareAndSetState(c, nextc))   return nextc == 0; }}

通過構造器 CountDownLatch end = new CountDownLatch(2);  state 被設置為2,所以c == 2,nextc = 2-1,

然后通過下面這個CAS操作將state設置為1。

protected final boolean compareAndSetState(int expect, int update) {  // See below for intrinsics setup to support this  return unsafe.compareAndSwapInt(this, stateOffset, expect, update); }

此時nextc還不為0,返回false。一直等到countDown()  方法被調用兩次,state == 0,nextc ==0,此時返回true。

進入doReleaseShared()方法。

doReleaseShared(); ↓private void doReleaseShared() { /*  * Ensure that a release propagates, even if there are other  * in-progress acquires/releases. This proceeds in the usual  * way of trying to unparkSuccessor of head if it needs  * signal. But if it does not, status is set to PROPAGATE to  * ensure that upon release, propagation continues.  * Additionally, we must loop in case a new node is added  * while we are doing this. Also, unlike other uses of  * unparkSuccessor, we need to know if CAS to reset status  * fails, if so rechecking.  */ for (;;) {  Node h = head;  if (h != null && h != tail) {   int ws = h.waitStatus;   if (ws == Node.SIGNAL) {    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))     continue;   // loop to recheck cases    unparkSuccessor(h);   }   else if (ws == 0 &&      !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))    continue;    // loop on failed CAS  }  if (h == head)     // loop if head changed   break; }}

回顧一下此時的等待隊列模型。

  +--------------------------+ prev   +------------------+head | waitStatus = Node.SIGNAL | <---- node(tail) | currentThread |  +--------------------------+     +------------------+

此時head 不為null,也不為tail,waitStatus == Node.SIGNAL,所以進入 if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) 這個判斷。

if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) ↓ /** * CAS waitStatus field of a node. */private static final boolean compareAndSetWaitStatus(Node node,              int expect,              int update) { return unsafe.compareAndSwapInt(node, waitStatusOffset,         expect, update);}

這個CAS 操作將 state 設置為 0 ,也就是說此時Head 中的 waitStatus 是0.此時隊列模型如下所示

  +----------------+ prev   +------------------+head | waitStatus = 0 | <---- node(tail) | currentThread |  +----------------+     +------------------+

該方法返回true。進入unparkSuccessor(h);

unparkSuccessor(h); ↓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)  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. */ Node s = node.next; 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; } if (s != null)  LockSupport.unpark(s.thread);}

s 就是head的后繼結點,也就是裝有當前線程的結點。s != null ,并且s.waitStatus ==0 ,所以進入 LockSupport.unpark(s.thread);

 public static void unpark(Thread thread) {  if (thread != null)   UNSAFE.unpark(thread); }

也就是unlock 被阻塞的線程。裁判被允許吹哨了!

countDown() 的原理就此就非常清晰了。

每執行一次countDown() 方法,state 就是減1,直到state == 0,則開始釋放被阻塞在隊列中的線程,根據前驅結點中waitStatus的狀態,釋放后續結點中的線程。

OK,回到上一篇文章的問題,什么時候跳出下面這個循環(await方法中的循環)

for (;;) { final Node p = node.predecessor(); if (p == head) {  int r = tryAcquireShared(arg);  if (r >= 0) {   setHeadAndPropagate(node, r);   p.next = null; // help GC   failed = false;   return;  } } if (shouldParkAfterFailedAcquire(p, node) &&  parkAndCheckInterrupt())  throw new InterruptedException();}

此時state == 0,所以進入 setHeadAndPropagate 方法。

setHeadAndPropagate(node, r); ↓private void setHeadAndPropagate(Node node, int propagate) { Node h = head; // Record old head for check below setHead(node); /*  * Try to signal next queued node if:  * Propagation was indicated by caller,  *  or was recorded (as h.waitStatus either before  *  or after setHead) by a previous operation  *  (note: this uses sign-check of waitStatus because  *  PROPAGATE status may transition to SIGNAL.)  * and  * The next node is waiting in shared mode,  *  or we don't know, because it appears null  *  * The conservatism in both of these checks may cause  * unnecessary wake-ups, but only when there are multiple  * racing acquires/releases, so most need signals now or soon  * anyway.  */ if (propagate > 0 || h == null || h.waitStatus < 0 ||  (h = head) == null || h.waitStatus < 0) {  Node s = node.next;  if (s == null || s.isShared())   doReleaseShared(); }} ↓private void setHead(Node node) { head = node; node.thread = null; node.prev = null;}

這個方法將head 的后繼結點變為head。該方法過后,又將node的next結點設置為null,模型變成下圖

  prev    +---------+ nextnull <---- node(tail/head) | null | ----> null       +---------+

也就是node head tail 什么的都被置為null,等待GC回收了,這個時候return,跳出了for循環,隊列被清空。

下面演示一下整個過程

 

setHeadAndPropagate(node, r);   +----------------+ head(tail) | waitStatus=0 |   | thread =null |   +----------------+     ↓   +----------------+   +----------------+   | waitStatus=0 | prev  | waitStatus=0 |head(tail) | thread =null | <---- node | currentThread |   +----------------+   +----------------+        ↓  +----------------+     +----------------+  | waitStatus=0 | prev   | waitStatus=0 |head | thread =null | <---- node(tail) | currentThread |  +----------------+     +----------------+     ↓  +----------------+     +----------------+  | Node.SIGNAL | prev   | waitStatus=0 |head | thread =null | <---- node(tail) | currentThread |  +----------------+     +----------------+       ↓  +----------------+     +----------------+  | waitStatus=0 | prev   | waitStatus=0 |head | thread =null | <---- node(tail) | currentThread |  +----------------+     +----------------+       ↓       +----------------+  prev    | waitStatus=0 | nextnull <---- node(tail/head) | null   | ----> null       +----------------+

CountDownLatch 的核心就是一個阻塞線程隊列,這是由鏈表構造而成的隊列,里面包含thread 和 waitStatus,其中waitStatus說明了后繼結點線程狀態。

state 是一個非常重要的標志,構造時,設置為對應的n值,如果n != 0,阻塞隊列將一直阻塞,除非中斷線程。

每次調用countDown()  方法,就是將state-1,而調用await() 方法就是將調用該方法的線程加入到阻塞隊列,直到state==0,才能釋放線程。

 以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品扒开腿做爽爽爽的视频| 亚洲综合在线做性| 亚洲精品电影网在线观看| 精品国产一区二区三区在线观看| www国产91| 亚洲成人久久久久| 日韩在线观看免费高清| 久久久久久久久久久免费精品| 亚洲欧洲日产国码av系列天堂| 久久福利视频导航| 在线日韩精品视频| 国产91露脸中文字幕在线| 日韩一区二区三区国产| 亚洲色图欧美制服丝袜另类第一页| 欧美大全免费观看电视剧大泉洋| 精品国模在线视频| 亚洲一区二区三区成人在线视频精品| wwwwwwww亚洲| 国产精品www网站| 91亚洲国产成人精品性色| 国产视频在线一区二区| 黄色91在线观看| 不卡av电影在线观看| 日韩精品久久久久久久玫瑰园| 国产免费久久av| 欧美一区二区三区艳史| 91久久国产精品| 久久高清视频免费| 91影院在线免费观看视频| 国产激情久久久| 久久精品视频中文字幕| 亚洲欧美日韩精品久久亚洲区| 日本精品一区二区三区在线| 97在线视频观看| 亚洲最大激情中文字幕| 日产精品久久久一区二区福利| 色哟哟网站入口亚洲精品| 国产精品久久久久久av福利| 亚洲第一在线视频| 久久综合亚洲社区| 97视频人免费观看| 亚洲成人a级网| 亚洲国产精品99久久| 国产91精品久久久久久久| 国模精品视频一区二区| 国产91精品在线播放| 亚洲精品小视频| 欧美日韩一区二区在线播放| 最近2019免费中文字幕视频三| 欧美精品免费看| 国产精品久久激情| 久久久久国产一区二区三区| 97精品国产97久久久久久| 欧美尺度大的性做爰视频| 国产精品视频99| 亚洲free嫩bbb| 欧美一级高清免费播放| 51午夜精品视频| 成人在线国产精品| 国产精品美女久久久免费| 久久久av亚洲男天堂| 91精品国产乱码久久久久久蜜臀| 日本一区二三区好的精华液| 成人网中文字幕| 亚洲天堂男人天堂女人天堂| 欧美成人激情视频| 国产精品国产三级国产专播精品人| 57pao成人永久免费视频| 影音先锋欧美精品| 国产精品久久久久999| 日韩av一区二区在线| 日韩av在线免费| 伊人成人开心激情综合网| 91夜夜未满十八勿入爽爽影院| 亚洲精品一区二三区不卡| 欧美国产日韩一区二区在线观看| 亚洲国产精久久久久久| 国产精品第8页| 成人福利免费观看| 久久久精品中文字幕| 中文字幕精品国产| 日韩免费在线免费观看| 91精品国产成人| 成人免费在线视频网站| 欧美在线视频一区| 国产欧美日韩免费看aⅴ视频| 国产精品女主播视频| 97视频在线观看视频免费视频| 欧美日韩国产一区二区| 日韩在线播放av| 久久久中精品2020中文| 久久久999精品| 欧美丰满老妇厨房牲生活| www.亚洲男人天堂| 88xx成人精品| 国产精品久久久久一区二区| 精品国产乱码久久久久久天美| 久青草国产97香蕉在线视频| 国产精品久久久久7777婷婷| 亚洲天堂网站在线观看视频| 亚洲自拍小视频| 亚洲日本中文字幕免费在线不卡| 精品性高朝久久久久久久| 日韩在线免费视频观看| 国产日韩欧美成人| 欧美三级欧美成人高清www| 亚洲天天在线日亚洲洲精| 欧美影院久久久| 色综合伊人色综合网| 美女视频久久黄| 欧美一区二区三区精品电影| 国产99久久久欧美黑人| 91久久久久久久久| 国产精品视频内| 亚洲jizzjizz日本少妇| 欧美午夜片欧美片在线观看| 久久久久999| 91在线视频精品| 欧美激情欧美激情在线五月| 亚洲桃花岛网站| 成人中心免费视频| 亚洲色图日韩av| 一本色道久久88综合日韩精品| 狠狠色狠狠色综合日日五| 在线电影欧美日韩一区二区私密| 久久这里只有精品视频首页| 亚洲黄色在线看| 欧美日本在线视频中文字字幕| 亚洲色图欧美制服丝袜另类第一页| 国产精品第8页| 久久久在线视频| 浅井舞香一区二区| 国产第一区电影| 日韩视频在线一区| 国产精品一区二区电影| 91在线观看免费网站| 日韩亚洲一区二区| 亚洲精品福利在线| 亚洲女人天堂视频| 国产精品444| 欧美成年人视频| 粉嫩av一区二区三区免费野| 欧美成aaa人片在线观看蜜臀| 欧美亚洲视频在线看网址| 欧美性色19p| 97av在线视频免费播放| 亚洲三级黄色在线观看| 欧美在线视频一区二区| 亚洲自拍欧美色图| 日韩精品电影网| 日韩高清不卡av| 久久精品美女视频网站| 亚洲毛片一区二区| 国产精品影院在线观看| 亚洲国产精品成人一区二区| 国产在线拍偷自揄拍精品| 国产精品自产拍在线观| 日韩中文字幕精品| 国产精品久久久久久久久男| 亚洲欧美日韩区| 成人午夜高潮视频| 日韩精品视频中文在线观看| 在线观看日韩欧美| 日韩a**站在线观看|