欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談Java并發(fā) J.U.C之AQS:CLH同步隊(duì)列

 更新時(shí)間:2019年05月21日 09:35:46   作者:chenssy  
AQS內(nèi)部維護(hù)著一個(gè)FIFO隊(duì)列,該隊(duì)列就是CLH同步隊(duì)列。下面小編來簡(jiǎn)單介紹下這個(gè)隊(duì)列

CLH同步隊(duì)列是一個(gè)FIFO雙向隊(duì)列,AQS依賴它來完成同步狀態(tài)的管理,當(dāng)前線程如果獲取同步狀態(tài)失敗時(shí),AQS則會(huì)將當(dāng)前線程已經(jīng)等待狀態(tài)等信息構(gòu)造成一個(gè)節(jié)點(diǎn)(Node)并將其加入到CLH同步隊(duì)列,同時(shí)會(huì)阻塞當(dāng)前線程,當(dāng)同步狀態(tài)釋放時(shí),會(huì)把首節(jié)點(diǎn)喚醒(公平鎖),使其再次嘗試獲取同步狀態(tài)。

在CLH同步隊(duì)列中,一個(gè)節(jié)點(diǎn)表示一個(gè)線程,它保存著線程的引用(thread)、狀態(tài)(waitStatus)、前驅(qū)節(jié)點(diǎn)(prev)、后繼節(jié)點(diǎn)(next),其定義如下:

static final class Node {
 /** 共享 */
 static final Node SHARED = new Node();

 /** 獨(dú)占 */
 static final Node EXCLUSIVE = null;

 /**
 * 因?yàn)槌瑫r(shí)或者中斷,節(jié)點(diǎn)會(huì)被設(shè)置為取消狀態(tài),被取消的節(jié)點(diǎn)時(shí)不會(huì)參與到競(jìng)爭(zhēng)中的,他會(huì)一直保持取消狀態(tài)不會(huì)轉(zhuǎn)變?yōu)槠渌麪顟B(tài);
 */
 static final int CANCELLED = 1;

 /**
 * 后繼節(jié)點(diǎn)的線程處于等待狀態(tài),而當(dāng)前節(jié)點(diǎn)的線程如果釋放了同步狀態(tài)或者被取消,將會(huì)通知后繼節(jié)點(diǎn),使后繼節(jié)點(diǎn)的線程得以運(yùn)行
 */
 static final int SIGNAL = -1;

 /**
 * 節(jié)點(diǎn)在等待隊(duì)列中,節(jié)點(diǎn)線程等待在Condition上,當(dāng)其他線程對(duì)Condition調(diào)用了signal()后,改節(jié)點(diǎn)將會(huì)從等待隊(duì)列中轉(zhuǎn)移到同步隊(duì)列中,加入到同步狀態(tài)的獲取中
 */
 static final int CONDITION = -2;

 /**
 * 表示下一次共享式同步狀態(tài)獲取將會(huì)無條件地傳播下去
 */
 static final int PROPAGATE = -3;

 /** 等待狀態(tài) */
 volatile int waitStatus;

 /** 前驅(qū)節(jié)點(diǎn) */
 volatile Node prev;

 /** 后繼節(jié)點(diǎn) */
 volatile Node next;

 /** 獲取同步狀態(tài)的線程 */
 volatile Thread thread;

 Node nextWaiter;

 final boolean isShared() {
 return nextWaiter == SHARED;
 }

 final Node predecessor() throws NullPointerException {
 Node p = prev;
 if (p == null)
 throw new NullPointerException();
 else
 return p;
 }

 Node() {
 }

 Node(Thread thread, Node mode) {
 this.nextWaiter = mode;
 this.thread = thread;
 }

 Node(Thread thread, int waitStatus) {
 this.waitStatus = waitStatus;
 this.thread = thread;
 }
}

CLH同步隊(duì)列結(jié)構(gòu)圖如下:

入列

學(xué)了數(shù)據(jù)結(jié)構(gòu)的我們,CLH隊(duì)列入列是再簡(jiǎn)單不過了,無非就是tail指向新節(jié)點(diǎn)、新節(jié)點(diǎn)的prev指向當(dāng)前最后的節(jié)點(diǎn),當(dāng)前最后一個(gè)節(jié)點(diǎn)的next指向當(dāng)前節(jié)點(diǎn)。代碼我們可以看看addWaiter(Node node)方法:

 private Node addWaiter(Node mode) {
 //新建Node
 Node node = new Node(Thread.currentThread(), mode);
 //快速嘗試添加尾節(jié)點(diǎn)
 Node pred = tail;
 if (pred != null) {
 node.prev = pred;
 //CAS設(shè)置尾節(jié)點(diǎn)
 if (compareAndSetTail(pred, node)) {
 pred.next = node;
 return node;
 }
 }
 //多次嘗試
 enq(node);
 return node;
 }

addWaiter(Node node)先通過快速嘗試設(shè)置尾節(jié)點(diǎn),如果失敗,則調(diào)用enq(Node node)方法設(shè)置尾節(jié)點(diǎn)

 private Node enq(final Node node) {
 //多次嘗試,直到成功為止
 for (;;) {
 Node t = tail;
 //tail不存在,設(shè)置為首節(jié)點(diǎn)
 if (t == null) {
 if (compareAndSetHead(new Node()))
 tail = head;
 } else {
 //設(shè)置為尾節(jié)點(diǎn)
 node.prev = t;
 if (compareAndSetTail(t, node)) {
 t.next = node;
 return t;
 }
 }
 }
 }

在上面代碼中,兩個(gè)方法都是通過一個(gè)CAS方法compareAndSetTail(Node expect, Node update)來設(shè)置尾節(jié)點(diǎn),該方法可以確保節(jié)點(diǎn)是線程安全添加的。在enq(Node node)方法中,AQS通過“死循環(huán)”的方式來保證節(jié)點(diǎn)可以正確添加,只有成功添加后,當(dāng)前線程才會(huì)從該方法返回,否則會(huì)一直執(zhí)行下去。

過程圖如下:

出列

CLH同步隊(duì)列遵循FIFO,首節(jié)點(diǎn)的線程釋放同步狀態(tài)后,將會(huì)喚醒它的后繼節(jié)點(diǎn)(next),而后繼節(jié)點(diǎn)將會(huì)在獲取同步狀態(tài)成功時(shí)將自己設(shè)置為首節(jié)點(diǎn),這個(gè)過程非常簡(jiǎn)單,head執(zhí)行該節(jié)點(diǎn)并斷開原首節(jié)點(diǎn)的next和當(dāng)前節(jié)點(diǎn)的prev即可,注意在這個(gè)過程是不需要使用CAS來保證的,因?yàn)橹挥幸粋€(gè)線程能夠成功獲取到同步狀態(tài)。過程圖如下:

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家

相關(guān)文章

  • java依賴jave-all-deps實(shí)現(xiàn)視頻格式轉(zhuǎn)換

    java依賴jave-all-deps實(shí)現(xiàn)視頻格式轉(zhuǎn)換

    jave-all-deps是一款基于FFmpeg庫(kù)的Java音視頻編解碼庫(kù),本文主要介紹了java依賴jave-all-deps實(shí)現(xiàn)視頻格式轉(zhuǎn)換,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-07-07
  • SpringBoot自定義FailureAnalyzer過程解析

    SpringBoot自定義FailureAnalyzer過程解析

    這篇文章主要介紹了SpringBoot自定義FailureAnalyzer,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • spring中bean id相同引發(fā)故障的分析與解決

    spring中bean id相同引發(fā)故障的分析與解決

    最近在工作中遇到了關(guān)于bean id相同引發(fā)故障的問題,通過查找相關(guān)資料終于解決了,下面這篇文章主要給大家介紹了因?yàn)閟pring中bean id相同引發(fā)故障的分析與解決方法,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-09-09
  • 淺談JSP是如何編譯成servlet并提供服務(wù)的

    淺談JSP是如何編譯成servlet并提供服務(wù)的

    JSP是Servlet的一種特殊形式,JSP頁面最終是編譯為Servlet執(zhí)行的,那么本文主要介紹了JSP是如何編譯成servlet并提供服務(wù)的,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • SpringBoot如何返回Json數(shù)據(jù)格式

    SpringBoot如何返回Json數(shù)據(jù)格式

    這篇文章主要介紹了SpringBoot如何返回Json數(shù)據(jù)格式問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • JavaWeb利用郵箱幫用戶找回密碼

    JavaWeb利用郵箱幫用戶找回密碼

    這篇文章主要為大家詳細(xì)介紹了JavaWeb利用郵箱幫用戶找回密碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • Java獲取Process子進(jìn)程進(jìn)程ID方法詳解

    Java獲取Process子進(jìn)程進(jìn)程ID方法詳解

    這篇文章主要介紹了Java獲取Process子進(jìn)程進(jìn)程ID方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12
  • java 連接Redis的小例子

    java 連接Redis的小例子

    這篇文章介紹了java 連接Redis的小例子,有需要的朋友可以參考一下
    2013-09-09
  • Java雪花算法生成分布式id詳解

    Java雪花算法生成分布式id詳解

    這篇文章主要介紹了Java雪花算法生成分布式id詳解,隨著業(yè)務(wù)的增長(zhǎng),有些表可能要占用很大的物理存儲(chǔ)空間,為了解決該問題,后期使用數(shù)據(jù)庫(kù)分片技術(shù),將一個(gè)數(shù)據(jù)庫(kù)進(jìn)行拆分,通過數(shù)據(jù)庫(kù)中間件連接,需要的朋友可以參考下
    2024-01-01
  • 查找native方法的本地實(shí)現(xiàn)函數(shù)native_function詳解

    查找native方法的本地實(shí)現(xiàn)函數(shù)native_function詳解

    JDK開放給用戶的源碼中隨處可見Native方法,被Native關(guān)鍵字聲明的方法說明該方法不是以Java語言實(shí)現(xiàn)的,而是以本地語言實(shí)現(xiàn)的,Java可以直接拿來用。這里介紹下查找native方法的本地實(shí)現(xiàn)函數(shù)native_function,感興趣的朋友跟隨小編一起看看吧
    2021-12-12

最新評(píng)論