AbstractQueuedSynchronizer(AQS)

摘要排隊同步器類
它提供了一個框架,用於實現阻塞鎖和相關的同步器,如信號量, CountDownLatch等。獲取的基本算法是try acquire,若是成功則返回其餘排隊線程(若是它還沒有排隊)並阻止當前線程。一樣,發佈的基本算法是try release,若是成功,則取消阻塞隊列中的第一個線程,不然只返回。線程將在先進先出(FIFO)等待隊列中等待。抽象方法 tryAcquire()和tryRelease()將根據須要由子類實現。html

以獨家模式獲取
以獨佔模式獲取的通用算法
AbstractQueuedSynchronizer(AQS)java

在上面的圖中'shouldParkAfterFailedAcquire?' 驗證前任的等待狀態是否爲SIGNAL。若是是,它肯定前任線程將在其釋放時SIGNAL,所以它將當即阻止,不然它可能會重試獲取鎖,以防它是隊列中的第一個節點。
AbstractQueuedSynchronizer(AQS)算法

隊列
若是線程沒法獲取鎖,它將被放入隊列中。若是隊列尚不存在,它將使用虛擬標頭初始化它,而後將其自身連接到它。頭部的「下一個」和節點的「上一個」將被連接。新節點也成了尾巴。標題節點的等待狀態將設置爲SIGNAL,以便當全部者線程釋放鎖時,它能夠通知頭節點的後繼者獲取鎖。線程將再次嘗試獲取鎖定以確保它在實際停放以前沒法獲取。安全

AbstractQueuedSynchronizer(AQS)框架

所以,只要其前任節點的等待狀態被設置爲SIGNAL,就能夠安全地停放未能得到鎖的線程,所以一旦前一個被釋放,它就能夠重試獲取鎖。
若是前一個被取消,它將跳過全部被取消的前任,以重置其等待線程的next和prev指針。ui

AbstractQueuedSynchronizer(AQS)
發佈
AbstractQueuedSynchronizer(AQS)線程

子類將根據他們的要求實現「try Release」。一旦發佈,標頭節點的後繼節點須要發信號,以便它能夠從新嘗試獲取。若是沒有頭,則表示隊列中沒有線程,所以沒有人發出信號。若是磁頭存在,則確保等待狀態不爲零。若是它爲零,則意味着不須要發信號通知後繼節點。指針

Unpark後繼節點的線程
線程到unpark是在後繼節點,一般只是下一個節點。
狀況1:若是頭部的等待狀態<0,則清除等待狀態。若是後繼節點(P1)未處於取消狀態,則取消後繼節點的線程,以便它能夠重試獲取。
AbstractQueuedSynchronizer(AQS)htm

狀況2:若是後繼節點取消或爲null,則從尾部向後遍歷以查找實際未取消的後繼節點。
AbstractQueuedSynchronizer(AQS)隊列

一旦取消停放線程,其節點就成了新頭。老頭將脫鉤。若是未能得到,將從新停放。頭節點的等待狀態設置爲0將重置爲SIGNAL。

發佈共享
這與獨家發佈相似。它還確保釋放傳播。

以共享模式獲取
這相似於獨家收購。它還將釋放傳播到隊列中等待獲取共享鎖的其餘等待線程。一旦鎖定被釋放,它就會取消其後繼節點的停放,後者又將釋放傳播到下一個節點。

取消
在嘗試獲取時可能存在運行時異常,在這種狀況下將取消上下文中的節點。若是節點被取消,咱們必須確保其後繼節點正確連接到有效的前任節點,所以可能必須調整連接。若是其前任節點已經處於取消狀態,則將跳過這些節點以到達具備等待狀態<= 0的適當的前任節點。
若是要取消的節點自己是尾節點,則將簡單地將其移除。它的前身節點將成爲新的尾巴。新尾部的「下一個」連接將指向null。
若是等待狀態<0,則表示後繼者須要信號,嘗試設置前任的下一個連接,以便得到一個。若是前任是頭節點自己,則它將喚醒其後繼節點。

狀況1:要取消的節點是尾節點
AbstractQueuedSynchronizer(AQS)

狀況2:取消節點的前任是head,如今將發信號通知被取消節點的下一個節點被喚醒。
原文地址:https://www.javarticles.com/2...

相關文章
相關標籤/搜索