AbstractQueuedSynchronizer 就是那個大名鼎鼎的 AQS,是java.util.concurrent包下同步器的核心。java
使用隊列的方式來解決n個線程來爭奪m把鎖的問題,每當一個新的線程須要獲取鎖,爲其建立一個節點並放到隊尾,若是該線程是隊列中的第一個節點,則節點的locked設置成false,若是它不是隊列的第一個節點,則它的節點的prev指向原來的隊尾節點,並不斷自旋查看prev指向節點的locked屬性,若是該值變爲false,表示輪到它來嘗試獲取鎖了,若是獲取成功並最終用完釋放後,則將本身的locked設置成false,若是獲取失敗,locked值不變,仍是true,並不斷嘗試獲取鎖。node
也就是說,每一個節點只須要關心前置節點的locked狀態,能夠發現CLH實現鎖的獲取是公平的。ui
Node節點維護了雙向節點和當前節點狀態和線程引用。this
static final class Node { volatile Node prev; volatile Node next; volatile Thread thread; volatile int waitStatus; // SIGNAL CANCELLED CONDITION PROPAGATE CANCELLED,值爲1,表示當前的線程被取消; SIGNAL,值爲-1,表示當前節點的後繼節點包含的線程須要運行,也就是unpark; CONDITION,值爲-2,表示當前節點在等待condition,也就是在condition隊列中; PROPAGATE,值爲-3,表示當前場景下後續的acquireShared可以得以執行; 值爲0,表示當前節點在sync隊列中,等待着獲取鎖。 }
* +------+ prev +-----+ +-----+ * head | | <---- | | <---- | | tail * +------+ +-----+ +-----+
須要在鎖定時,須要維護一個狀態(int類型),而對狀態的操做是原子和非阻塞的,經過同步器提供的對狀態訪問的方法對狀態進行操縱,並基於Unsafe的原子操做來修改state的狀態,compareAndSet來確保原子性的修改。線程
獲取/設置當前的同步狀態:code
protected final int getState() { return state; } protected final void setState(int newState) { state = newState; }
對同步狀態對修改採用原子操做:隊列
protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); }
入隊操做,若是隊列爲空則實例化節點,不然插入隊尾:get
private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } enq(node); return node; }
獲取鎖: 須要獲取當前節點的前驅節點,而且頭結點可以獲取狀態,表明可以佔有鎖。同步
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
這個方法在非公平實現中,主要是經過AQS的state來檢查和維護鎖狀態,若是state是0,說明沒有線程佔有這個鎖,若是不爲0而且鎖的佔有線程是當前線程,則是重入的狀況,都可以得到鎖並修改state值。it
若是是首次得到鎖,則設置鎖佔有線程爲當前線程。
固然,若是前面兩種狀況都不知足,說明嘗試得到鎖失敗,須要作前面段落所述的隊列操做,建立一個等待結點並進入循環,循環中的park()調用掛起當前線程。
不然將當前線程掛起:
LockSupport.park最終把線程交給系統(Linux)內核進行阻塞。
private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); }
public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
若是修改state值成功,則找到隊列中應該喚起的結點,對節點中的線程調用unpark()方法,恢復線程執行。