最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java并發(fā)系列之AbstractQueuedSynchronizer源碼分析(概要分析)

 更新時(shí)間:2018年02月27日 10:30:14   作者:勞夫子  
這篇文章主要為大家詳細(xì)介紹了Java并發(fā)系列之AbstractQueuedSynchronizer源碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

學(xué)習(xí)Java并發(fā)編程不得不去了解一下java.util.concurrent這個(gè)包,這個(gè)包下面有許多我們經(jīng)常用到的并發(fā)工具類(lèi),例如:ReentrantLock, CountDownLatch, CyclicBarrier, Semaphore等。而這些類(lèi)的底層實(shí)現(xiàn)都依賴(lài)于AbstractQueuedSynchronizer這個(gè)類(lèi),由此可見(jiàn)這個(gè)類(lèi)的重要性。所以在Java并發(fā)系列文章中我首先對(duì)AbstractQueuedSynchronizer這個(gè)類(lèi)進(jìn)行分析,由于這個(gè)類(lèi)比較重要,而且代碼比較長(zhǎng),為了盡可能分析的透徹一些,我決定用四篇文章對(duì)該類(lèi)進(jìn)行一個(gè)比較完整的介紹。本篇文章作為概要介紹主要是讓讀者們對(duì)該類(lèi)有個(gè)初步了解。為了敘述簡(jiǎn)單,后續(xù)有些地方會(huì)用AQS代表這個(gè)類(lèi)。

1. AbstractQueuedSynchronizer這個(gè)類(lèi)是干嘛的?

相信要許多讀者使用過(guò)ReentrantLock,但是卻不知道AbstractQueuedSynchronizer的存在。其實(shí)ReentrantLock實(shí)現(xiàn)了一個(gè)內(nèi)部類(lèi)Sync,該內(nèi)部類(lèi)繼承了AbstractQueuedSynchronizer,所有鎖機(jī)制的實(shí)現(xiàn)都是依賴(lài)于Sync內(nèi)部類(lèi),也可以說(shuō)ReentrantLock的實(shí)現(xiàn)就是依賴(lài)于AbstractQueuedSynchronizer類(lèi)。于此類(lèi)似,CountDownLatch, CyclicBarrier, Semaphore這些類(lèi)也是采用同樣的方式來(lái)實(shí)現(xiàn)自己對(duì)于鎖的控制。可見(jiàn),AbstractQueuedSynchronizer是這些類(lèi)的基石。那么AQS內(nèi)部到底實(shí)現(xiàn)了什么以至于所以這些類(lèi)都要依賴(lài)于它呢?可以這樣說(shuō),AQS為這些類(lèi)提供了基礎(chǔ)設(shè)施,也就是提供了一個(gè)密碼鎖,這些類(lèi)擁有了密碼鎖之后可以自己來(lái)設(shè)置密碼鎖的密碼。此外,AQS還提供了一個(gè)排隊(duì)區(qū),并且提供了一個(gè)線(xiàn)程訓(xùn)導(dǎo)員,我們知道線(xiàn)程就像一個(gè)原始的野蠻人,它不懂得講禮貌,它只會(huì)橫沖直撞,所以你得一步一步去教它,告訴它什么時(shí)候需要去排隊(duì)了,要到哪里去排隊(duì),排隊(duì)前要做些什么,排隊(duì)后要做些什么。這些教化工作全部都由AQS幫你完成了,從它這里教化出來(lái)的線(xiàn)程都變的非常文明懂禮貌,不再是原始的野蠻人,所以以后我們只需要和這些文明的線(xiàn)程打交道就行了,千萬(wàn)不要和原始線(xiàn)程有過(guò)多的接觸!

2. 為何說(shuō)AbstractQueuedSynchronizer提供了一把密碼鎖?

//同步隊(duì)列的頭結(jié)點(diǎn)
private transient volatile Node head; 

//同步隊(duì)列的尾結(jié)點(diǎn)
private transient volatile Node tail;

//同步狀態(tài)
private volatile int state;

//獲取同步狀態(tài)
protected final int getState() {
 return state;
}

//設(shè)置同步狀態(tài)
protected final void setState(int newState) {
 state = newState;
}

//以CAS方式設(shè)置同步狀態(tài)
protected final boolean compareAndSetState(int expect, int update) {
 return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

上面的代碼列出了AQS的所有成員變量,可以看到AQS的成員變量只有三個(gè),分別是同步隊(duì)列頭結(jié)點(diǎn)引用,同步隊(duì)列尾結(jié)點(diǎn)引用以及同步狀態(tài)。注意,這三個(gè)成員變量都使用了volatile關(guān)鍵字進(jìn)行修飾,這就確保了多個(gè)線(xiàn)程對(duì)它的修改都是內(nèi)存可見(jiàn)的。整個(gè)類(lèi)的核心就是這個(gè)同步狀態(tài),可以看到同步狀態(tài)其實(shí)就是一個(gè)int型的變量,大家可以把這個(gè)同步狀態(tài)看成一個(gè)密碼鎖,而且還是從房間里面鎖起來(lái)的密碼鎖,state具體的值就相當(dāng)于密碼控制著密碼鎖的開(kāi)合。當(dāng)然這個(gè)鎖的密碼是多少就由各個(gè)子類(lèi)來(lái)規(guī)定了,例如在ReentrantLock中,state等于0表示鎖是開(kāi)的,state大于0表示鎖是鎖著的,而在Semaphore中,state大于0表示鎖是開(kāi)的,state等于0表示鎖是鎖著的。

3. AbstractQueuedSynchronizer的排隊(duì)區(qū)是怎樣實(shí)現(xiàn)的?

AbstractQueuedSynchronizer內(nèi)部其實(shí)有兩個(gè)排隊(duì)區(qū),一個(gè)是同步隊(duì)列,一個(gè)是條件隊(duì)列。從上圖可以看出,同步隊(duì)列只有一條,而條件隊(duì)列可以有多條。同步隊(duì)列的結(jié)點(diǎn)分別持有前后結(jié)點(diǎn)的引用,而條件隊(duì)列的結(jié)點(diǎn)只有一個(gè)指向后繼結(jié)點(diǎn)的引用。圖中T表示線(xiàn)程,每個(gè)結(jié)點(diǎn)包含一個(gè)線(xiàn)程,線(xiàn)程在獲取鎖失敗后首先進(jìn)入同步隊(duì)列排隊(duì),而想要進(jìn)入條件隊(duì)列該線(xiàn)程必須持有鎖才行。接下來(lái)我們看看隊(duì)列中每個(gè)結(jié)點(diǎn)的結(jié)構(gòu)。

//同步隊(duì)列的結(jié)點(diǎn)
static final class Node {
 
 static final Node SHARED = new Node(); //表示當(dāng)前線(xiàn)程以共享模式持有鎖
 
 static final Node EXCLUSIVE = null; //表示當(dāng)前線(xiàn)程以獨(dú)占模式持有鎖

 static final int CANCELLED = 1;  //表示當(dāng)前結(jié)點(diǎn)已經(jīng)取消獲取鎖
 
 static final int SIGNAL = -1;  //表示后繼結(jié)點(diǎn)的線(xiàn)程需要運(yùn)行
 
 static final int CONDITION = -2;  //表示當(dāng)前結(jié)點(diǎn)在條件隊(duì)列中排隊(duì)
 
 static final int PROPAGATE = -3;  //表示后繼結(jié)點(diǎn)可以直接獲取鎖

 volatile int waitStatus; //表示當(dāng)前結(jié)點(diǎn)的等待狀態(tài)
 
 volatile Node prev;  //表示同步隊(duì)列中的前繼結(jié)點(diǎn)

 volatile Node next;  //表示同步隊(duì)列中的后繼結(jié)點(diǎn) 

 volatile Thread thread; //當(dāng)前結(jié)點(diǎn)持有的線(xiàn)程引用
 
 Node nextWaiter;   //表示條件隊(duì)列中的后繼結(jié)點(diǎn)

 //當(dāng)前結(jié)點(diǎn)狀態(tài)是否是共享模式
 final boolean isShared() {
  return nextWaiter == SHARED;
 }

 //返回當(dāng)前結(jié)點(diǎn)的前繼結(jié)點(diǎn)
 final Node predecessor() throws NullPointerException {
  Node p = prev;
  if (p == null) {
   throw new NullPointerException();
  } else {
   return p;
  }
 }
 
 //構(gòu)造器1
 Node() {}
 
 //構(gòu)造器2, 默認(rèn)用這個(gè)構(gòu)造器
 Node(Thread thread, Node mode) {
  //注意持有模式是賦值給nextWaiter
  this.nextWaiter = mode;
  this.thread = thread;
 }
 
 //構(gòu)造器3, 只在條件隊(duì)列中用到
 Node(Thread thread, int waitStatus) {
  this.waitStatus = waitStatus;
  this.thread = thread;
 }
}

Node代表同步隊(duì)列和條件隊(duì)列中的一個(gè)結(jié)點(diǎn),它是AbstractQueuedSynchronizer的內(nèi)部類(lèi)。Node有很多屬性,比如持有模式,等待狀態(tài),同步隊(duì)列中的前繼和后繼,以及條件隊(duì)列中的后繼引用等等??梢园淹疥?duì)列和條件隊(duì)列看成是排隊(duì)區(qū),每個(gè)結(jié)點(diǎn)看成是排隊(duì)區(qū)的座位,將線(xiàn)程看成是排隊(duì)的客人。客人剛來(lái)時(shí)會(huì)先去敲敲門(mén),看看鎖有沒(méi)有開(kāi),如果鎖沒(méi)開(kāi)它就會(huì)去排隊(duì)區(qū)領(lǐng)取一個(gè)號(hào)碼牌,聲明自己想要以什么樣的方式來(lái)持有鎖,最后再到隊(duì)列的末尾進(jìn)行排隊(duì)。

4 怎樣理解獨(dú)占模式和共享模式?

前面講到每個(gè)客人在排隊(duì)前會(huì)領(lǐng)取一個(gè)號(hào)碼牌,聲明自己想要以什么樣的方式來(lái)占有鎖,占有鎖的方式分為獨(dú)占模式和共享模式,那么怎樣來(lái)理解獨(dú)占模式和共享模式呢?實(shí)在找不到什么好的比喻,大家可以聯(lián)想一下公共廁所,獨(dú)占模式的人比較霸道,老子要么就不進(jìn),進(jìn)來(lái)了就不許別人再進(jìn)了,自己一個(gè)人獨(dú)自占用整個(gè)廁所。共享模式的人就沒(méi)那么講究了,當(dāng)它發(fā)現(xiàn)這個(gè)廁所已經(jīng)可以用了之后,它自己進(jìn)來(lái)還不算,還得熱心的問(wèn)下后面的人介不介意一起用,如果后面的人不介意一起使用那就不用再排隊(duì)了大家一起上就是了, 當(dāng)然如果后面的人介意那就只好留在隊(duì)列里繼續(xù)排隊(duì)了。

5 怎樣理解結(jié)點(diǎn)的等待狀態(tài)?

我們還看到每個(gè)結(jié)點(diǎn)都有一個(gè)等待狀態(tài),這個(gè)等待狀態(tài)分為CANCELLED,SIGNAL,CONDITION,PROPAGATE四種狀態(tài)??梢詫⑦@個(gè)等待狀態(tài)看作是掛在座位旁邊的牌子,標(biāo)識(shí)當(dāng)前座位上的人的等待狀態(tài)。這個(gè)牌子的狀態(tài)不僅自己可以修改,其他人也可以修改。例如當(dāng)這個(gè)線(xiàn)程在排隊(duì)過(guò)程中已經(jīng)打算放棄了,它就會(huì)將自己座位上的牌子設(shè)置為CANCELLED,這樣其他人看到了就可以將它清理出隊(duì)列。還有一種情況是,當(dāng)線(xiàn)程在座位上要睡著之前,它怕自己睡過(guò)了頭,就會(huì)將前面位置上的牌子改為SIGNAL,因?yàn)槊總€(gè)人在離開(kāi)隊(duì)列前都會(huì)回到自己座位上看一眼,如果看到牌子上狀態(tài)為SIGNAL,它就會(huì)去喚醒下一個(gè)人。只有保證前面位置上的牌子為SIGNAL,當(dāng)前線(xiàn)程才會(huì)安心的睡去。CONDITION狀態(tài)表示該線(xiàn)程在條件隊(duì)列中排隊(duì),PROPAGATE狀態(tài)提醒后面來(lái)的線(xiàn)程可以直接獲取鎖,這個(gè)狀態(tài)只在共享模式用到,后面單獨(dú)講共享模式的時(shí)候會(huì)講到。

6. 結(jié)點(diǎn)進(jìn)入同步隊(duì)列時(shí)會(huì)進(jìn)行哪些操作?

//結(jié)點(diǎn)入隊(duì)操作, 返回前一個(gè)結(jié)點(diǎn)
private Node enq(final Node node) {
 for (;;) {
  //獲取同步隊(duì)列尾結(jié)點(diǎn)引用
  Node t = tail;
  //如果尾結(jié)點(diǎn)為空說(shuō)明同步隊(duì)列還沒(méi)有初始化
  if (t == null) {
   //初始化同步隊(duì)列
   if (compareAndSetHead(new Node())) {
    tail = head;
   }
  } else {
   //1.指向當(dāng)前尾結(jié)點(diǎn)
   node.prev = t;
   //2.設(shè)置當(dāng)前結(jié)點(diǎn)為尾結(jié)點(diǎn)
   if (compareAndSetTail(t, node)) {
    //3.將舊的尾結(jié)點(diǎn)的后繼指向新的尾結(jié)點(diǎn)
    t.next = node;
    //for循環(huán)唯一的出口
    return t;
   }
  }
 }
}

注意,入隊(duì)操作使用一個(gè)死循環(huán),只有成功將結(jié)點(diǎn)添加到同步隊(duì)列尾部才會(huì)返回,返回結(jié)果是同步隊(duì)列原先的尾結(jié)點(diǎn)。下圖演示了整個(gè)操作過(guò)程。

讀者需要注意添加尾結(jié)點(diǎn)的順序,分為三步:指向尾結(jié)點(diǎn),CAS更改尾結(jié)點(diǎn),將舊尾結(jié)點(diǎn)的后繼指向當(dāng)前結(jié)點(diǎn)。在并發(fā)環(huán)境中這三步操作不一定能保證完成,所以在清空同步隊(duì)列所有已取消的結(jié)點(diǎn)這一操作中,為了尋找非取消狀態(tài)的結(jié)點(diǎn),不是從前向后遍歷而是從后向前遍歷的。還有就是每個(gè)結(jié)點(diǎn)進(jìn)入隊(duì)列中時(shí)它的等待狀態(tài)是為0,只有后繼結(jié)點(diǎn)的線(xiàn)程需要掛起時(shí)才會(huì)將前面結(jié)點(diǎn)的等待狀態(tài)改為SIGNAL。

注:以上全部分析基于JDK1.7,不同版本間會(huì)有差異,讀者需要注意。

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

相關(guān)文章

  • 從零開(kāi)始學(xué)JAVA之可變參數(shù)

    從零開(kāi)始學(xué)JAVA之可變參數(shù)

    本文是從零開(kāi)始學(xué)JAVA的第一篇,屬于Java基礎(chǔ)知識(shí)介紹的第一部分,主要介紹Java的可變參數(shù),非常使用,希望對(duì)大家有所幫助
    2014-10-10
  • 解決scala.collection.mutable.Map寫(xiě)入的問(wèn)題

    解決scala.collection.mutable.Map寫(xiě)入的問(wèn)題

    這篇文章主要介紹了解決scala.collection.mutable.Map寫(xiě)入的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Mybatis逆工程的使用

    Mybatis逆工程的使用

    最近在學(xué)Mybatis,類(lèi)似Hibernate,Mybatis也有逆工程可以直接生成代碼(mapping,xml,pojo),方便快速開(kāi)發(fā)。這篇文章給大家介紹Mybatis逆工程的使用相關(guān)知識(shí),感興趣的朋友一起看下吧
    2016-06-06
  • Spring6整合JUnit的詳細(xì)步驟

    Spring6整合JUnit的詳細(xì)步驟

    這篇文章主要介紹了Spring6整合JUnit的詳細(xì)步驟,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • SpringCloud中的服務(wù)接口(api)

    SpringCloud中的服務(wù)接口(api)

    這篇文章主要介紹了SpringCloud中的服務(wù)接口(api),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • jackson json序列化實(shí)現(xiàn)首字母大寫(xiě),第二個(gè)字母需小寫(xiě)

    jackson json序列化實(shí)現(xiàn)首字母大寫(xiě),第二個(gè)字母需小寫(xiě)

    這篇文章主要介紹了jackson json序列化實(shí)現(xiàn)首字母大寫(xiě),第二個(gè)字母需小寫(xiě)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • java面向?qū)ο蟮牧瓌t一法則小結(jié)

    java面向?qū)ο蟮牧瓌t一法則小結(jié)

    本篇文章主要對(duì)java面向?qū)ο蟮牧瓌t一法則進(jìn)行簡(jiǎn)要說(shuō)明,具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-01-01
  • 詳解Spring AOP的實(shí)現(xiàn)方式

    詳解Spring AOP的實(shí)現(xiàn)方式

    AOP是一種思想,是對(duì)某一類(lèi)事情的集中處理,切面就是指某一類(lèi)特定的問(wèn)題,所以AOP可以理解為面向特定方法編程,這篇文章主要介紹了Spring AOP的實(shí)現(xiàn)方式,需要的朋友可以參考下
    2024-02-02
  • SpringBoot使用Hibernate攔截器實(shí)現(xiàn)時(shí)間自動(dòng)注入的操作代碼

    SpringBoot使用Hibernate攔截器實(shí)現(xiàn)時(shí)間自動(dòng)注入的操作代碼

    這篇文章主要介紹了SpringBoot使用Hibernate攔截器實(shí)現(xiàn)時(shí)間自動(dòng)注入的操作代碼,主要包括hibernate攔截器的相關(guān)知識(shí),結(jié)合實(shí)例代碼給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-10-10
  • Java 面試題和答案 - (下)

    Java 面試題和答案 - (下)

    本文主要介紹Java 面試題,這里整理了Java面試題關(guān)于JDBC,線(xiàn)程異常處理,Servlet,JSP的知識(shí)的整理,幫助大家理解知識(shí)點(diǎn),便于面試,有興趣的小伙伴可以參考下
    2016-09-09

最新評(píng)論

桐城市| 新营市| 延津县| 呼和浩特市| 玉屏| 建湖县| 合江县| 岑巩县| 阜新| 临城县| 太原市| 灵武市| 大关县| 浦县| 湘潭县| 临安市| 永济市| 莫力| 黑水县| 德兴市| 广德县| 维西| 阳江市| 沂源县| 杭州市| 蓝田县| 新津县| 屏南县| 延安市| 穆棱市| 苍溪县| 化德县| 潜江市| 精河县| 雅江县| 新巴尔虎右旗| 法库县| 丽江市| 三河市| 聊城市| 天柱县|