AbstractQueuedSynchronizer即抽象隊(duì)列同步器,AQS定義了一套多線(xiàn)程訪問(wèn)共享資源的同步器框架,許多同步類(lèi)實(shí)現(xiàn)都依賴(lài)于它,如常用的ReentrantLock/Semaphore/CountDownLatch。 它維護(hù)了一個(gè)volatile int state(代表共享資源)和一個(gè)FIFO雙端隊(duì)列(多線(xiàn)程爭(zhēng)用阻塞時(shí)線(xiàn)程進(jìn)入此隊(duì)列尾部,隊(duì)列頭節(jié)點(diǎn)是成功獲取鎖的線(xiàn)程,當(dāng)頭節(jié)點(diǎn)釋放鎖時(shí),會(huì)喚醒后面節(jié)點(diǎn)并釋放當(dāng)前頭節(jié)點(diǎn)的引用)。 AQS定義兩種資源共享方式:Exclusive(獨(dú)占,只有一個(gè)線(xiàn)程能執(zhí)行,如ReentrantLock)和Share(共享,多個(gè)線(xiàn)程可同時(shí)執(zhí)行,如Semaphore/CountDownLatch)。 不同自定義同步器爭(zhēng)用共享資源的方式也不同。自定義同步器在實(shí)現(xiàn)時(shí)只需要實(shí)現(xiàn)共享資源state的獲取與釋放方式即可,至于具體線(xiàn)程等待隊(duì)列的維護(hù)(如獲取資源失敗入隊(duì)/喚醒出隊(duì)等),AQS已經(jīng)在頂層實(shí)現(xiàn)好了。
獨(dú)占鎖的獲取流程 (1)調(diào)用入口方法acquire(arg) (2)調(diào)用模版方法tryAcquire(arg)嘗試獲取鎖,若成功則返回,若失敗則走下一步 (3)將當(dāng)前線(xiàn)程構(gòu)造成一個(gè)Node節(jié)點(diǎn),并利用CAS將其加入到同步隊(duì)列尾部,然后該節(jié)點(diǎn)對(duì)應(yīng)線(xiàn)程進(jìn)入自旋狀態(tài) (4)自旋時(shí)首先判斷其前驅(qū)節(jié)點(diǎn)釋放為頭節(jié)點(diǎn)&是否成功獲取同步狀態(tài),兩個(gè)條件都成立,則將當(dāng)前線(xiàn)程的節(jié)點(diǎn)設(shè)置為頭節(jié)點(diǎn),如果不是,則利用LockSupport.park(this)將當(dāng)前線(xiàn)程掛起 ,等待被前驅(qū)節(jié)點(diǎn)喚醒
獨(dú)占鎖的釋放流程 (1)調(diào)用入口方法release(arg) (2)調(diào)用模版方法tryRelease(arg)釋放同步狀態(tài) (3)獲取同步隊(duì)列中當(dāng)前節(jié)點(diǎn)的下一節(jié)點(diǎn) (4)利用LockSupport.unpark(currentNode.next.thread)喚醒后繼節(jié)點(diǎn)
共享鎖的獲取流程 (1)調(diào)用acquireShared(arg)入口方法 (2)進(jìn)入tryAcquireShared(arg)方法獲取同步狀態(tài),如果返回值>=0,說(shuō)明同步狀態(tài)(state)有剩余,獲取鎖成功直接返回 如果返回值<0,說(shuō)明獲取同步狀態(tài)失敗,向隊(duì)列尾部添加一個(gè)共享類(lèi)型的Node節(jié)點(diǎn),隨即該節(jié)點(diǎn)進(jìn)入自旋狀態(tài) (3)自旋時(shí),首先檢查前驅(qū)節(jié)點(diǎn)釋放為頭節(jié)點(diǎn)&tryAcquireShared()是否>=0(即成功獲取同步狀態(tài))。如果是則說(shuō)明當(dāng)前節(jié)點(diǎn)可執(zhí)行,把當(dāng)前節(jié)點(diǎn)設(shè)置為頭節(jié)點(diǎn)并喚醒所有后繼節(jié)點(diǎn);如果否,則利用LockSupport.unpark(this)掛起當(dāng)前線(xiàn)程,等待被前驅(qū)節(jié)點(diǎn)喚醒
共享鎖的釋放流程 重入鎖 重入鎖指是當(dāng)前線(xiàn)成功獲取鎖后,如果再次訪問(wèn)該臨界區(qū)則不會(huì)對(duì)自己產(chǎn)生互斥行為。ReentrantLock和synchronized都是可重入鎖,synchronized由jvm實(shí)現(xiàn)可重入,ReentrantLock基于AQS實(shí)現(xiàn)可重入。 ReentrantLock可重入的原理是判斷上次獲取鎖的線(xiàn)程是否為當(dāng)前線(xiàn)程,如果是則可再次進(jìn)入臨界區(qū),如果不是則阻塞。
非公平鎖與公平鎖 非公平鎖是指當(dāng)鎖狀態(tài)為可用時(shí),不管在當(dāng)前鎖上是否有其他線(xiàn)程在等待,新近線(xiàn)程都有機(jī)會(huì)搶占鎖。 公平鎖是指當(dāng)多個(gè)線(xiàn)程嘗試獲取鎖時(shí),成功獲取鎖的順序與請(qǐng)求獲取鎖的順序相同。 AQS實(shí)現(xiàn)中兩者區(qū)別在于是否判斷當(dāng)前節(jié)點(diǎn)存在前驅(qū)節(jié)點(diǎn)!hasQueuedPredecessors() &&,如果當(dāng)前線(xiàn)程獲取鎖失敗就會(huì)被加入到AQS同步隊(duì)列,那么如果同步隊(duì)列中的節(jié)點(diǎn)存在前驅(qū)節(jié)點(diǎn),也就表明存在線(xiàn)程比當(dāng)前節(jié)點(diǎn)線(xiàn)程更早獲取鎖,只有等待前面線(xiàn)程釋放鎖后才能獲取鎖。
讀寫(xiě)鎖 基于AQS的讀寫(xiě)鎖實(shí)現(xiàn)ReentrantReadWriteLock,該讀寫(xiě)鎖實(shí)現(xiàn)原理是:將同步變量state按照高16位和低16位拆分,高16位表示讀鎖,低16位表示寫(xiě)鎖。 寫(xiě)鎖的獲取 (1)獲取同步狀態(tài),從中分離出低16位的寫(xiě)鎖狀態(tài) (2)如果同步狀態(tài)不為0,說(shuō)明存在讀鎖或?qū)戞i (3)如果存在讀鎖(c !=0 && w == 0),則不能獲取寫(xiě)鎖(保證寫(xiě)對(duì)讀的可見(jiàn)性) (4)如果當(dāng)前線(xiàn)程不是上次獲取寫(xiě)鎖的線(xiàn)程,則不能獲取寫(xiě)鎖(寫(xiě)鎖為獨(dú)占鎖) (5)如果以上判斷均通過(guò),則在低16位同步狀態(tài)上利用CAS進(jìn)行修改(增加寫(xiě)鎖同步狀態(tài),實(shí)現(xiàn)可重入) (6)將當(dāng)前線(xiàn)程設(shè)置為寫(xiě)鎖的獲取線(xiàn)程 寫(xiě)鎖的釋放與獨(dú)占鎖類(lèi)似,不斷減少讀鎖同步狀態(tài),同步狀態(tài)為0時(shí),寫(xiě)鎖完全釋放
讀鎖(共享鎖)的獲取 (1)獲取當(dāng)前同步狀態(tài) (2)計(jì)算高16為讀鎖狀態(tài) 1后的值 (3)如果大于能夠獲取到的讀鎖的最大值,則拋出異常 (4)如果存在寫(xiě)鎖并且當(dāng)前線(xiàn)程不是寫(xiě)鎖的獲取者,則獲取讀鎖失敗 (5)如果上述判斷都通過(guò),則利用CAS重新設(shè)置讀鎖的同步狀態(tài) 來(lái)源:http://www./content-4-120601.html
|