1. 父類AbstractOwnableSynchronizer
該類有兩個重要的方法,設(shè)置獨占線程與獲取獨占線程讲岁。
public abstract class AbstractOwnableSynchronizer
implements java.io.Serializable {
/** Use serial ID even though all fields transient. */
private static final long serialVersionUID = 3737899427754241961L;
/**
* 空構(gòu)造方法
*/
protected AbstractOwnableSynchronizer() { }
/**
* 同步器獨占模式當前線程
*/
private transient Thread exclusiveOwnerThread;
/**
* 設(shè)置當前獨占線程
*/
protected final void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
/**
* 獲取當前獨占線程
*/
protected final Thread getExclusiveOwnerThread() {
return exclusiveOwnerThread;
}
}
2. Node節(jié)點
用Node作為同步隊列和條件隊列的節(jié)點缓艳。
static final class Node {
/** 共享模式中的節(jié)點 */
static final Node SHARED = new Node();
/** 獨占模式中的節(jié)點 */
static final Node EXCLUSIVE = null;
/** 當線程等待超時或者被中斷阶淘,則取消等待溪窒,設(shè)等待狀態(tài)為-1澈蚌,進入取消狀態(tài)則不再變化 */
static final int CANCELLED = 1;
/** 后繼節(jié)點處于等待狀態(tài)灼狰,當前節(jié)點(為-1)被取消或者中斷時會通知后繼節(jié)點伏嗜,使后繼節(jié)點的線程得以運行 */
static final int SIGNAL = -1;
/** 當前節(jié)點處于等待隊列伐厌,節(jié)點線程等待在Condition上挣轨,當其他線程對condition執(zhí)行signall方法時卷扮,等待隊列轉(zhuǎn)移到同步隊列晤锹,加入到對同步狀態(tài)的獲取 */
static final int CONDITION = -2;
/**
* 值為-3鞭铆,與共享模式相關(guān)车遂,在共享模式中斯辰,該狀態(tài)標識結(jié)點的線程處于可運行狀態(tài)
*/
static final int PROPAGATE = -3;
/**
* 等待狀態(tài)
*/
volatile int waitStatus;
/**
* 指向前節(jié)點
*/
volatile Node prev;
/**
* 指向后節(jié)點
*/
volatile Node next;
/**
* 進入該節(jié)點的線程
*/
volatile Thread thread;
/**
* 指向條件隊列中的下一個節(jié)點
*/
Node nextWaiter;
/**
* 當節(jié)點在共享模式中等待時返回true
*/
final boolean isShared() {
return nextWaiter == SHARED;
}
/**
* 返回前一節(jié)點
*/
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { // Used to establish initial head or SHARED marker
}
Node(Thread thread, Node mode) { // 被addWaiter方法調(diào)用
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) { // 被條件隊列使用
this.waitStatus = waitStatus;
this.thread = thread;
}
}
3. 成員變量
包含三個成員變量衣陶,head祖搓、tail以及state
/**
* 等待隊列的頭結(jié)點,如果頭結(jié)點存在的話拯欧,它的waitStatus不能是CANCELLED
*/
private transient volatile Node head;
/**
* 等待隊列的尾節(jié)點
*/
private transient volatile Node tail;
/**
* 同步器狀態(tài)
*/
private volatile int state;
4. 主要方法
4.1 同步器狀態(tài)相關(guān)
/**
* 獲取當前同步器狀態(tài)
*/
protected final int getState() {
return state;
}
/**
* 設(shè)置當前同步器狀態(tài)
*/
protected final void setState(int newState) {
state = newState;
}
/**
* 調(diào)用魔法類的CAS方法,設(shè)置同步器狀態(tài)
*/
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
4.2 acquire(int arg)方法
先嘗試獲取同步狀態(tài)该贾,如果獲取成功(同步狀態(tài)為0捌臊,表示可以獲取),直接返回曙寡;否則該線程加到等待隊列中進行排隊举庶。
/**
* 以獨占模式獲取户侥,忽略中斷蕊唐。 通過調(diào)用至少一次tryAcquire(int)實現(xiàn)烁设,成功返回署尤。
* 否則線程排隊曹体,可能會重復(fù)阻塞和解除阻塞硝烂,直到成功才調(diào)用tryAcquire(int) 。 該方法可用于實現(xiàn)方法Lock.lock() 串稀。
*/
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
4.3 tryAcquire(int arg)方法
交給子類實現(xiàn)
4.4 addWaiter(Node mode)方法
將新節(jié)點加到尾部
/**
* 在尾部添加節(jié)點
*/
private Node addWaiter(Node mode) {
// 構(gòu)建一個新node母截,nextWaiter是當前node
Node node = new Node(Thread.currentThread(), mode);
// 獲取尾結(jié)點
Node pred = tail;
// 如果尾節(jié)點不為空清寇,將當前節(jié)點作為尾結(jié)點
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//尾節(jié)點為空华烟,將當前節(jié)點入隊
enq(node);
return node;
}
4.5 enq(final Node node)方法
將當前節(jié)點入隊盔夜。
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { //尾結(jié)點為空返十,必須初始化
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
4.6 acquireQueued(final Node node, int arg)方法
不斷自旋嘗試獲取同步狀態(tài)(鎖)吧慢,獲取不成功检诗,則阻塞節(jié)點中的線程逢慌。
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
//自旋獲取同步狀態(tài)
for (;;) {
//獲取前一個節(jié)點
final Node p = node.predecessor();
//如果前一個節(jié)點是頭結(jié)點并且獲取同步狀態(tài)成功攻泼,就將當前節(jié)點置為頭結(jié)點
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) // 休眠線程并返回中斷狀態(tài)
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
4.7 release(int arg)方法
在獨占模式中釋放節(jié)點。當返回true的時候牛欢,unblocking一個或多個線程傍睹。
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
4.8 tryRelease(int arg)方法
嘗試釋放同步狀態(tài)拾稳,留給子類實現(xiàn)
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
4.9 unparkSuccessor(Node node)方法
喚醒線程
private void unparkSuccessor(Node node) {
// 獲取wait狀態(tài)
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/**
* 若后繼結(jié)點為空访得,或狀態(tài)為CANCEL(已失效)陕凹,則從后尾部往前遍歷找到最前的一個處于正常阻塞狀態(tài)的結(jié)點
* 進行喚醒
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);//喚醒線程
}
4.10 acquireShared(int arg)方法
在共享模式中獲得鎖传趾。
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
4.11 tryAcquireShared(int arg)
嘗試獲取鎖磕仅,當返回值大于等于0時榕订,表示能夠獲取到同步狀態(tài)蜕便,空方法留給子類實現(xiàn)劫恒。
4.12 doAcquireShared(int arg)方法
如果當前節(jié)點的前驅(qū)為頭節(jié)點時,嘗試獲取同步狀態(tài)
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
4.13 releaseShared(int arg)方法
該方法在釋放同步狀態(tài)之后轿腺,將會喚醒后續(xù)處于等待狀態(tài)的節(jié)點两嘴。對于能夠支持多個線 程同時訪問的并發(fā)組件(比如Semaphore),它和獨占式主要區(qū)別在于tryReleaseShared(int arg) 方法必須確保同步狀態(tài)(或者資源數(shù))線程安全釋放族壳,一般是通過循環(huán)和CAS來保證的憔辫,因為 釋放同步狀態(tài)的操作會同時來自多個線程。
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}