自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

學(xué)Java的竟然有人不會(huì)AQS機(jī)制

開發(fā) 后端
Java中的并發(fā)包大家應(yīng)該都或多或少的了解過,說到并發(fā)包也就不得不提我們今天要說的AbstractQueuedSynchronizer,簡(jiǎn)稱AQS,這個(gè)是很多并發(fā)工具類的實(shí)現(xiàn)基礎(chǔ).

Java中的并發(fā)包大家應(yīng)該都或多或少的了解過,說到并發(fā)包也就不得不提我們今天要說的AbstractQueuedSynchronizer,簡(jiǎn)稱AQS,這個(gè)是很多并發(fā)工具類的實(shí)現(xiàn)基礎(chǔ)

  1. public abstract class AbstractQueuedSynchronizer 
  2.     extends AbstractOwnableSynchronizer 
  3.     implements java.io.Serializable 

類如其名,抽象的隊(duì)列式的同步器,AQS定義了一套多線程訪問共享資源的同步器框架,許多同步類實(shí)現(xiàn)都依賴于它,如常用的ReentrantLock、Semaphore、CountDownLatch

深入探究AQS

 

先來看這個(gè)圖,圖中有顏色的為Method,無(wú)顏色的為Attribution

總的來說,AQS框架共分為五層,自上而下由淺入深,從AQS對(duì)外暴露的API到底層基礎(chǔ)數(shù)據(jù)

當(dāng)有自定義同步器接入時(shí),只需重寫第一層所需要的部分方法即可,不需要關(guān)注底層具體的實(shí)現(xiàn)流程

道理也很簡(jiǎn)單,就像我們說的,這個(gè)東西是一個(gè)抽象的同步器,它將加鎖和解鎖這些操作交給了具體的實(shí)現(xiàn)類來自己實(shí)現(xiàn),就像這樣

當(dāng)自定義同步器進(jìn)行加鎖或者解鎖操作時(shí),先經(jīng)過第一層的API進(jìn)入AQS內(nèi)部方法,然后經(jīng)過第二層進(jìn)行鎖的獲取,獲取鎖成功之后便直接執(zhí)行相應(yīng)的邏輯,對(duì)于獲取鎖失敗的流程,進(jìn)入第三層和第四層的等待隊(duì)列處理,而這些處理方式均依賴于第五層的基礎(chǔ)數(shù)據(jù)提供層

這樣給大家說的話,應(yīng)該很容易就可以理解了

AQS的實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)

研究過AQS的同學(xué)應(yīng)該對(duì)這個(gè)圖都很熟悉了,AQS的核心就是state+Node+CLH變體雙向隊(duì)列

核心思想就是通過一個(gè)volatile類型state狀態(tài)來表示共享資源的狀態(tài),如果被請(qǐng)求的資源空閑,就將獲得共享資源的線程設(shè)置為當(dāng)前有效的線程,然后修改state為鎖定狀態(tài),其它的線程及時(shí)可見

共享資源被占用之后,其它線程肯定不能直接就返回失敗啊,這樣這個(gè)并發(fā)包的高效就沒得了,所以就引入了一個(gè)雙向隊(duì)列,這個(gè)雙向等待隊(duì)列放置那些暫時(shí)還未搶到共享資源的線程,來完成等待喚醒機(jī)制

實(shí)際上,AQS的運(yùn)行中的這個(gè)CLH變體的雙向隊(duì)列,不知存儲(chǔ)未搶到共享資源的線程,而搶到共享資源的這個(gè)線程也會(huì)作為隊(duì)列的頭節(jié)點(diǎn)head存在

CLH:Craig、Landin and Hagersten隊(duì)列,是單向鏈表,AQS中的隊(duì)列是CLH變體的虛擬雙向隊(duì)列(FIFO),AQS是通過將每條請(qǐng)求共享資源的線程封裝成一個(gè)節(jié)點(diǎn)來實(shí)現(xiàn)鎖的分配。

這么說大家應(yīng)該就很容易懂了吧,就是大家一起搶共享資源,搶到的就是有效線程,放到雙向隊(duì)列的head頭節(jié)點(diǎn),沒搶到的就依次往后排

我們接著看一下Node節(jié)點(diǎn)是怎么做的

這個(gè)是Node節(jié)點(diǎn)的屬性值和含義

簡(jiǎn)單解釋一下,waitStatus就是節(jié)點(diǎn)在隊(duì)列中的狀態(tài),Thread就是當(dāng)前節(jié)點(diǎn)的線程,prev和next是前驅(qū)指針和后繼指針

這里的重點(diǎn)就是waitStatus屬性

CANCELLED(1):表示當(dāng)前結(jié)點(diǎn)已取消調(diào)度。當(dāng)timeout或被中斷(響應(yīng)中斷的情況下),會(huì)觸發(fā)變更為此狀態(tài),進(jìn)入該狀態(tài)后的結(jié)點(diǎn)將不會(huì)再變化。

SIGNAL(-1):表示后繼結(jié)點(diǎn)在等待當(dāng)前結(jié)點(diǎn)喚醒。后繼結(jié)點(diǎn)入隊(duì)時(shí),會(huì)將前繼結(jié)點(diǎn)的狀態(tài)更新為SIGNAL。

CONDITION(-2):表示結(jié)點(diǎn)等待在Condition上,當(dāng)其他線程調(diào)用了Condition的signal()方法后,CONDITION狀態(tài)的結(jié)點(diǎn)將從等待隊(duì)列轉(zhuǎn)移到同步隊(duì)列中,等待獲取同步鎖。

PROPAGATE(-3):共享模式下,前繼結(jié)點(diǎn)不僅會(huì)喚醒其后繼結(jié)點(diǎn),同時(shí)也可能會(huì)喚醒后繼的后繼結(jié)點(diǎn)。

0:新結(jié)點(diǎn)入隊(duì)時(shí)的默認(rèn)狀態(tài)。

正是由于這個(gè)特點(diǎn),負(fù)值表示結(jié)點(diǎn)處于有效等待狀態(tài),而正值表示結(jié)點(diǎn)已被取消。所以源碼中很多地方用>0、<0來判斷結(jié)點(diǎn)的狀態(tài)是否正常

同步狀態(tài)state

AQS中維護(hù)了一個(gè)名為state的字段,意為同步狀態(tài),是由Volatile修飾的,用于展示當(dāng)前臨界資源的獲鎖情況。

  1. private volatile int state; 

對(duì)于這個(gè)state,AQS也是提供了幾個(gè)方法

這幾個(gè)方法都是final類型的,子類是無(wú)法修改的

在AQS中的是有兩種加鎖模式的,一種是共享式,一種是獨(dú)占式,共享式也很簡(jiǎn)單,就是通過控制AQS中的state數(shù)值即可

state是AQS中的volatile類型,具有可見性,用于記錄加鎖狀態(tài)和重入的次數(shù),當(dāng)然不只是重入次數(shù),其實(shí)這個(gè)state在不同的實(shí)現(xiàn)類中是有不同的意義的

【ReentrantLock】:state用于記錄鎖的持有狀態(tài)和重入次數(shù),state=0表示沒有線程持有鎖;state=1表示有一個(gè)線程持有鎖;state=N表示exclusiveOwnerThread這個(gè)線程N(yùn)次重入了這個(gè)鎖。

【ReentrantReadWriteLock】:state用于記錄讀寫鎖的占用狀態(tài)和持有線程數(shù)量(讀鎖)、重入次數(shù)(寫鎖),state的高16位記錄持有讀鎖的線程數(shù)量,低16位記錄寫鎖線程重入次數(shù),如果這16位的值是0,表示沒有線程占用鎖,否則表示有線程持有鎖。

另外針對(duì)讀鎖,每個(gè)線程獲取到的讀鎖次數(shù)由本地線程變量中的HoldCounter記錄。

【Semaphore】:state用于計(jì)數(shù)。state=N表示還有N個(gè)信號(hào)量可以分配出去,state=0表示沒有信號(hào)量了,此時(shí)所有需要acquire信號(hào)量的線程都等著;

【CountDownLatch】:state也用于計(jì)數(shù),每次countDown都減一,減到0的時(shí)候喚醒被await阻塞的線程。

切記:區(qū)分開volatile類型的state屬性和Node節(jié)點(diǎn)中的waitStatus屬性

搶占共享資源也是有兩種方式的:公平鎖和非公平鎖

大家用過ReentrantLock的同學(xué)肯定都知道,默認(rèn)的是非公平鎖,但是我們可以傳入一個(gè)參數(shù)設(shè)置為公平鎖

按照ReentrantLock來說一下公平鎖和非公平鎖

公平鎖,是公平的,可以保證獲取鎖的線程按照先來后到的順序,獲取到鎖。

非公平鎖,各個(gè)線程獲取到鎖的順序,不一定和它們申請(qǐng)的先后順序一致,有可能后來的線程,反而先獲取到了鎖。

在實(shí)現(xiàn)上,公平鎖在進(jìn)行l(wèi)ock時(shí),首先會(huì)進(jìn)行tryAcquire()操作。

在tryAcquire中,會(huì)判斷等待隊(duì)列中是否已經(jīng)有別的線程在等待了。如果隊(duì)列中已經(jīng)有別的線程了,則tryAcquire失敗,則將自己加入隊(duì)列。

如果隊(duì)列中沒有別的線程,則進(jìn)行獲取鎖的操作。

非公平鎖,在進(jìn)行l(wèi)ock時(shí),會(huì)直接嘗試進(jìn)行加鎖,如果成功,則獲取到鎖,如果失敗,則進(jìn)行和公平鎖相同的動(dòng)作。

從公平鎖和非公平的實(shí)現(xiàn)上來看,他們的操作基本相同,唯一的區(qū)別在于,在lock時(shí),非公平鎖會(huì)直接先進(jìn)行嘗試加鎖的操作。

當(dāng)前一個(gè)線程完成了鎖的使用,并且釋放了,而且此時(shí)等待隊(duì)列非空時(shí),如果這是有新線程申請(qǐng)鎖,那么,公平鎖和非公平鎖的表現(xiàn)就會(huì)出現(xiàn)差異。

公平鎖

優(yōu)點(diǎn):線程按照順序獲取鎖,不會(huì)出現(xiàn)餓死現(xiàn)象(注:餓死現(xiàn)象是指一個(gè)線程的CPU執(zhí)行時(shí)間都被其他線程占用,導(dǎo)致得不到CPU執(zhí)行。

缺點(diǎn):整體吞吐效率相對(duì)非公平鎖要低,等待隊(duì)列中除一個(gè)線程以外的所有線程都會(huì)阻塞,CPU喚醒線程的開銷比非公平鎖要大。

非公平鎖

優(yōu)點(diǎn):可以減少喚起線程上下文切換的消耗,整體吞吐量比公平鎖高。

缺點(diǎn):在高并發(fā)環(huán)境下可能造成線程優(yōu)先級(jí)反轉(zhuǎn)和餓死現(xiàn)象。

AQS作為并發(fā)編程的框架,為很多其他同步工具提供了良好的解決方案。下面列出了JUC中的幾種同步工具,大體介紹一下AQS的應(yīng)用場(chǎng)景:

 

責(zé)任編輯:姜華 來源: Java賊船
相關(guān)推薦

2015-07-20 15:26:56

WiFi感知

2020-11-03 06:57:10

MyBatis數(shù)據(jù)庫(kù)

2019-09-18 15:20:16

MyBatisSQL數(shù)據(jù)庫(kù)

2022-11-09 10:46:18

AQS加鎖機(jī)制

2022-09-04 12:43:03

算法裁員Meta

2020-07-07 07:37:36

Integer源碼Java

2019-06-14 08:48:46

Tomcat日志SpringBoot

2021-02-03 20:19:08

Istio流量網(wǎng)格

2020-11-02 08:35:59

內(nèi)存數(shù)據(jù)庫(kù)Redis

2018-09-11 08:05:44

千兆路由器廠商

2021-07-05 18:05:40

SpringBean方法

2017-03-07 17:45:42

Windows磁盤碎片整理

2021-06-10 09:00:33

單例模式數(shù)據(jù)庫(kù)

2024-10-09 09:07:10

JVM優(yōu)化String類JDK1.6

2020-11-27 09:16:21

BlockingQue

2022-02-14 12:04:43

前綴SpringJpa

2021-05-11 10:40:29

JUCAQSJava

2021-05-12 15:16:17

JUCAQSJava

2016-06-07 09:23:05

瀏覽器技巧快捷鍵

2020-07-19 15:39:37

Python開發(fā)工具
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)