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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

多线程:AQS的一些心得

發布時間:2025/3/21 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 多线程:AQS的一些心得 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

AQS作為JUC并發組件實現的核心。全稱是AbstructQueuedSynchronizer,也就是同步隊列器。

其內部實現主要的是一個state狀態標識和基于FIFO一個同步隊列

這個狀態標識表明當前的資源是否是可以爭取的,當state=0是,表示資源沒有加鎖;當state>0時,表示資源加鎖。

關于這個隊列,有幾個屬性:


1)隊列是基于雙向鏈表的,因此具有定制的節點結構信息。node

2)tail尾指針,指向隊列的最后一個節點

3)頭指針,指向隊列的第一個節點(也即是? ?頭節點)。頭結點中包含有當前資源的同步狀態信息。

4)waitStatus 節點等待標識。

=1時? ?SIGNAL? ?表明當前節點的后繼節點所包含的線程需要運行。

=-1? ? CANCEL? 表明當前節點線程取消

=-2? ? CONDITION 表明當前節點在等待condition? 處于Condition等待隊列

=-3? ? PROPAGATE? 應用在共享鎖中

?= 0? ?當前節點在同步隊列中,等待獲取鎖

?


AQS是通過內部的同步隊列來完成線程獲取資源的排隊工作

AQS可以實現獨占鎖和共享鎖。

ReentrantLock實現的是獨占鎖;ReentrantReadWriteLock實現的是獨占鎖和共享鎖;CountDownLatch實現的是共享鎖。

因此,關于鎖的獲取和釋放有以下幾種方式:

1)獨占式獲取鎖

首先,線程嘗試獲得鎖tryAcquire,獲取成功則函數返回,獲得失敗,addWaiter構造一個獨占模式同步節點,如果前驅節點不為空則將該節點采用CAS方式放置到同步隊列尾部,如果放置失敗則說明當前節點位置存在并發競爭,進入enq方法進行添加,其實,enq方法也就是通過CAS自旋鎖的方式不斷地嘗試來向隊列中添加構造的節點;

如果節點最后成功地放置到隊列里。執行acquireQueued方法,當前節點中的線程通過自旋方式嘗試獲取同步狀態。

如果當前節點的前驅節點是頭結點,并且重新嘗試獲取鎖成功,就將當前節點設置為頭結點!否則判斷當前線程是否可以被安全阻塞掛起(根據waitStatus來判斷,判斷函數shouldParkAfterFailedAcquire),是的話就調用parkAndCheckInterrupt方法里的park方法進行掛起。然后再次進入for循環自旋。

如何判斷????


當前節點的前驅節點是waitStatus是SIGNAL則可以掛起,之后由前驅節點進行喚醒;

若前驅節點是CANCEL 則向前遍歷直到找到一個是SIGNAL的節點,并將當前節點放置在此節點的后面,不能掛起;

否則嘗試將前驅節點的狀態設置為SIGNAL,不能掛起

?

2)獨占式釋放鎖

調用release方法來釋放鎖。這個方法一般由子類自己重寫。

首先,嘗試釋放tryRelease,如果成功那么就喚醒后繼節點? ? unparkSuccessor里的LockSupport.unpark方法

?

3)共享式獲得鎖

調用acquireShared方法,首先嘗試獲得鎖,獲得成功就返回;獲得失敗進入等待隊列。直到獲取到資源為止才返回。

若當前節點的前驅節點是頭結點,則嘗試進行加鎖;如果加鎖成功就調用setHeadAndPropagate,將當前節點設置為頭結點,喚醒后繼節點,并將之前的頭結點從隊列中踢出去,等待GC回收;

shared模式下是允許多個線程持有一把鎖的,其中tryAcquire的返回值標志了是否允許其他線程繼續進入。如果允許的話,需要喚醒隊列中等待的線程。其中setHeadAndPropagate方法中的doReleaseShared方法的邏輯很簡單,就是喚醒后繼線程。

如果獲得鎖失敗,判斷當前線程是否可以被安全阻塞掛起,是的話就調用parkAndCheckInterrupt方法里的park方法進行掛起。

tryAcquireShared返回值為正,說明獲得鎖成功,負數則失敗。

?

4)共享式釋放鎖

調用releaseShared方法;嘗試釋放鎖,釋放成功再次調用doReleaseShared,此方法內部還是調用LockSupport.unpark()方法喚醒后繼線程。

?

5)獨占超時獲得鎖

相比于獨占獲得鎖方式,最重要的區別就是:獨占獲得鎖在自旋獲得鎖失敗之后會掛起,讓出CPU時間片,之后再次進入for循環自旋嘗試獲得鎖;而獨占超時獲得鎖在獲得鎖失敗之后,判斷當前時間是否超時?若超時,則直接返回不再進行for循環;若沒有超時,則將當前線程阻塞指定的超時時間之后再次進行for循環進行CAS自旋獲取鎖!

調用doAcquireNanos方法。該方法在自旋過程中,當節點的前驅節點為頭節點時嘗試獲取同步狀態,如果獲取成功則從該方法返回,這個過程和獨占式同步獲取的過程類似,

但是在同步狀態獲取失敗的處理上有所不同。如果當前線程獲取同步狀態失敗,則首先重新計算超時間隔nanosTimeout,則判斷是否超時(nanosTimeout小于等于0表示已經超時),如果沒有超時,則使當前線程等待nanosTimeout納秒(當已到設置的超時時間,該線程會從LockSupport.parkNanos(Object blocker,long nanos)方法返回)。

如果nanosTimeout小于等于spinForTimeoutThreshold(1000納秒)時,將不會使該線程進行超時等待,而是進入快速的自旋過程。原因在于,非常短的超時等待無法做到十分精確,如果這時再進行超時等待,相反會讓nanosTimeout的超時從整體上表現得反而不精確。因此,在超時非常短的場景下,同步器會進入無條件的快速自旋。

?

詳情請參見本博客多線程模塊AQS源碼分析文章

?

總結

以上是生活随笔為你收集整理的多线程:AQS的一些心得的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。