AQS理解之五—并发编程中AQS的理解
AQS理解之五—并發編程中AQS的理解
首先看下uml類圖:
AbstractOwnableSynchronizer 這個類定義是提供一個創建鎖的基礎,設置一個排它線程,幫助控制和監控訪問。
先看下AbstractQueuedSynchronizer 這個類的內部變量。
Head和tail是兩個Node變量。
int型的state。
long型的spinForTimeoutThreshold(自旋超時閾值,為固定1000 nanoseconds)
一個Unsafe類和5個unsafe偏移量
先看看Node類。
可以看源碼和uml圖看出,Node節點組成雙向鏈表(prev和next),持有一個線程thread,有一個waitStatus,可能會有5種狀態(SIGNAL,CANCELLED,CONDITION,PROPAGATE,初始值0),提供了2個方法,是否共享和返回非空前置節點。
static final class Node {/** Marker to indicate a node is waiting in shared mode */static final Node SHARED = new Node();/** Marker to indicate a node is waiting in exclusive mode */static final Node EXCLUSIVE = null;/** waitStatus value to indicate thread has cancelled */static final int CANCELLED = 1;/** waitStatus value to indicate successor's thread needs unparking */static final int SIGNAL = -1;/** waitStatus value to indicate thread is waiting on condition */static final int CONDITION = -2;/*** waitStatus value to indicate the next acquireShared should* unconditionally propagate*/static final int PROPAGATE = -3;/*** Status field, taking on only the values:* SIGNAL: The successor of this node is (or will soon be)* blocked (via park), so the current node must* unpark its successor when it releases or* cancels. To avoid races, acquire methods must* first indicate they need a signal,* then retry the atomic acquire, and then,* on failure, block.* CANCELLED: This node is cancelled due to timeout or interrupt.* Nodes never leave this state. In particular,* a thread with cancelled node never again blocks.* CONDITION: This node is currently on a condition queue.* It will not be used as a sync queue node* until transferred, at which time the status* will be set to 0. (Use of this value here has* nothing to do with the other uses of the* field, but simplifies mechanics.)* PROPAGATE: A releaseShared should be propagated to other* nodes. This is set (for head node only) in* doReleaseShared to ensure propagation* continues, even if other operations have* since intervened.* 0: None of the above** The values are arranged numerically to simplify use.* Non-negative values mean that a node doesn't need to* signal. So, most code doesn't need to check for particular* values, just for sign.** The field is initialized to 0 for normal sync nodes, and* CONDITION for condition nodes. It is modified using CAS* (or when possible, unconditional volatile writes).*/volatile int waitStatus;/*** Link to predecessor node that current node/thread relies on* for checking waitStatus. Assigned during enqueuing, and nulled* out (for sake of GC) only upon dequeuing. Also, upon* cancellation of a predecessor, we short-circuit while* finding a non-cancelled one, which will always exist* because the head node is never cancelled: A node becomes* head only as a result of successful acquire. A* cancelled thread never succeeds in acquiring, and a thread only* cancels itself, not any other node.*/volatile Node prev;/*** Link to the successor node that the current node/thread* unparks upon release. Assigned during enqueuing, adjusted* when bypassing cancelled predecessors, and nulled out (for* sake of GC) when dequeued. The enq operation does not* assign next field of a predecessor until after attachment,* so seeing a null next field does not necessarily mean that* node is at end of queue. However, if a next field appears* to be null, we can scan prev's from the tail to* double-check. The next field of cancelled nodes is set to* point to the node itself instead of null, to make life* easier for isOnSyncQueue.*/volatile Node next;/*** The thread that enqueued this node. Initialized on* construction and nulled out after use.*/volatile Thread thread;/*** Link to next node waiting on condition, or the special* value SHARED. Because condition queues are accessed only* when holding in exclusive mode, we just need a simple* linked queue to hold nodes while they are waiting on* conditions. They are then transferred to the queue to* re-acquire. And because conditions can only be exclusive,* we save a field by using special value to indicate shared* mode.*/Node nextWaiter;/*** Returns true if node is waiting in shared mode.*/final boolean isShared() {return nextWaiter == SHARED;}/*** Returns previous node, or throws NullPointerException if null.* Use when predecessor cannot be null. The null check could* be elided, but is present to help the VM.** @return the predecessor of this node*/final Node predecessor() throws NullPointerException {Node p = prev;if (p == null)throw new NullPointerException();elsereturn p;}Node() { // Used to establish initial head or SHARED marker}Node(Thread thread, Node mode) { // Used by addWaiterthis.nextWaiter = mode;this.thread = thread;}Node(Thread thread, int waitStatus) { // Used by Conditionthis.waitStatus = waitStatus;this.thread = thread;} }幾個比較重要的方法getState() ,compareAndSetState,setExclusiveOwnerThread,setState(nextc)。
分別看下其中的實現:
state是一個可以用作記錄狀態的volatile參數,用作鎖的時候,用他來記錄一個線程進入鎖的次數。如果state = 0時,則說明當前線程釋放了鎖,其他線程可以獲取。
getExclusiveOwnerThread 這個獲取到當前操作的線程,如果不為null,且不相等,則不能獲取到鎖。
Node是一個鏈表,記錄著阻塞等待的線程,如果要為公平版本,可以按順序在Node中取,如果不是,則不用判斷是否下一個是否當前線程,誰搶占到誰執行。
waitStatus記錄的是當前某個Node節點的狀態。
Node節點之前我們幾節看的都是用的排他鎖,Exclusive的版本,AQS中還定義了一個Shared來表示共享版本。
總結
AQS將實現Java鎖的一套公共邏輯進行了抽象,定義了一個模版,如果我們想實現自己的鎖,則可以繼承它來快速實現。JAVA中常見的ReentrantLock,Semaphore(信號量),coutDownLatch,線程池中的Worker等都繼承它實現了自己的鎖。不過在每個實現類中,state的意義可能不大相同,如可重入鎖中代表的是重入的次數/是否有鎖,而信號量中代表剩余可以進入的線程數,這些都可以通過看源碼來繼續學習。
總結
以上是生活随笔為你收集整理的AQS理解之五—并发编程中AQS的理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AQS理解之四—看看我们写的和 Reen
- 下一篇: AQS理解之六,AQS的其他实现类