1. 線(xiàn)程安全
多個(gè)線(xiàn)程對(duì)公共資源進(jìn)行非原子操作,就會(huì)存在線(xiàn)程安全問(wèn)題
- 多線(xiàn)程環(huán)境
- 多個(gè)線(xiàn)程共享一個(gè)資源
- 對(duì)資源進(jìn)行非原子性操作
2. Lock 接口介紹
Java中鎖的實(shí)現(xiàn)可以由synchronized關(guān)鍵字來(lái)完成,jdk1.5之后出現(xiàn)了一種新的方式來(lái)實(shí)現(xiàn)——Lock接口。
/**
* 1.采用Lock,必須主動(dòng)去釋放鎖,并且在發(fā)生異常時(shí),不會(huì)自動(dòng)釋放鎖。 <br>
* 2.因此一般來(lái)說(shuō),使用Lock必須在try{}catch{}塊中進(jìn)行,并且將釋放鎖的操作放在finally塊中進(jìn)行,以保證鎖一定被被釋放,防止死鎖的發(fā)生
*/
public interface Lock {
/**
* 獲取鎖。 如果鎖不可用,出于線(xiàn)程調(diào)度目的,將禁用當(dāng)前線(xiàn)程,并且在獲得鎖之前,該線(xiàn)程將一直處于休眠狀態(tài)。
*/
void lock();
/**
* 可中斷獲取鎖,當(dāng)通過(guò)這個(gè)方法去獲取鎖時(shí),如果線(xiàn)程正在等待獲取鎖(休眠中),則這個(gè)線(xiàn)程能夠響應(yīng)中斷,即中斷線(xiàn)程的等待狀態(tài)<br>
* 注意:當(dāng)一個(gè)線(xiàn)程獲取了鎖之后,是不會(huì)被interrupt()方法中斷的
*/
void lockInterruptibly() throws InterruptedException;
/**
* 如果鎖可用,則獲取鎖,并立即返回值 true。如果鎖不可用,則此方法將立即返回值 false。
*/
boolean tryLock();
/**
* 如果鎖可用,則此方法將立即返回值 true。如果鎖不可用,出于線(xiàn)程調(diào)度目的,將禁用當(dāng)前線(xiàn)程,并且在發(fā)生以下三種情況之一前,該線(xiàn)程將一直處于休眠狀態(tài):
* <ul>
* <li>1、鎖由當(dāng)前線(xiàn)程獲得;
* <li>2、或者 其他某個(gè)線(xiàn)程中斷當(dāng)前線(xiàn)程,并且支持對(duì)鎖獲取的中斷;
* <li>3、或者 已超過(guò)指定的等待時(shí)間
* </ul>
*/
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
/**
* 釋放鎖。
*/
void unlock();
/**
* 返回綁定到此 Lock 實(shí)例的新 Condition 實(shí)例。<br>
* 在等待條件前,鎖必須由當(dāng)前線(xiàn)程保持。調(diào)用 Condition.await() 將在等待前以原子方式釋放鎖,并在等待返回前重新獲取鎖。
*/
Condition newCondition();
}
3. ReentrantLock重入鎖
ReentrantLock,意思是“可重入鎖”,Lock接口有三個(gè)實(shí)現(xiàn)類(lèi)分別是ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock。后面兩個(gè)是內(nèi)部類(lèi)。
首先讓我們先簡(jiǎn)單的看看ReentrantLock類(lèi)中都有哪些方法,不喜歡可以直接跳過(guò)
/**
* 除了實(shí)現(xiàn) Lock 接口,此類(lèi)還定義了 isLocked 和 getLockQueueLength 方法,以及一些相關(guān)的 protected
* 訪(fǎng)問(wèn)方法,這些方法對(duì)檢測(cè)和監(jiān)視可能很有用。
*/
public class ReentrantLock implements Lock, java.io.Serializable {
private final Sync sync;
/**
* 為了將此類(lèi)用作同步器的基礎(chǔ),需要適當(dāng)?shù)刂匦露x以下方法。<br>
*
* <li>{@link #tryAcquire}
* <li>{@link #tryRelease}
* <li>{@link #tryAcquireShared}
* <li>{@link #tryReleaseShared}
* <li>{@link #isHeldExclusively}
*
* 這是通過(guò)使用 getState()、setState(int)或 compareAndSetState(int, int)
* 方法來(lái)檢查或修改同步狀態(tài)來(lái)實(shí)現(xiàn)的
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
重寫(xiě)的父類(lèi)方法tryRelease
protected final boolean tryRelease(int releases) {
return false;
}
}
static final class NonfairSync extends Sync {
重寫(xiě)的父類(lèi)方法tryAcquire
protected final boolean tryAcquire(int acquires) {
return false;
}
}
static final class FairSync extends Sync {
重寫(xiě)的父類(lèi)方法tryAcquire
protected final boolean tryAcquire(int acquires) {
return false;
}
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
以下是核心實(shí)現(xiàn)Lock接口的方法,我們可以看出,以下方法都是調(diào)用了內(nèi)部類(lèi)Sync
/**
* 獲取鎖,成功直接返回(計(jì)數(shù)加 1),失敗則線(xiàn)程阻塞
*/
public void lock() {
sync.acquire(1);
}
/**
* 中斷獲取鎖,成功直接返回(計(jì)數(shù)加 1)<br>
* 失敗則當(dāng)前線(xiàn)程進(jìn)入休眠狀態(tài),直到以下兩個(gè)事件發(fā)生
* <li>1. 當(dāng)前線(xiàn)程獲取鎖成功
* <li>2. 當(dāng)前線(xiàn)程被其他線(xiàn)程中斷
*/
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
/**
* 嘗試非阻塞的獲取鎖,調(diào)用該方法立即返回,true表示獲取到鎖(計(jì)數(shù)加1)<br>
* 同時(shí)這個(gè)鎖是不遵守公平設(shè)置的,如果想遵守公平設(shè)置獲取鎖可以使用 tryLock(0, TimeUnit.SECONDS)}
*/
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
/**
* 超時(shí)獲取鎖,同時(shí)這個(gè)方法遵守公平設(shè)置 。 以下情況會(huì)返回:
* <li>時(shí)間內(nèi)獲取到了鎖,
* <li>時(shí)間內(nèi)被中斷,
* <li>時(shí)間到了沒(méi)有獲取到鎖。
*/
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
/**
* 釋放鎖,如果當(dāng)前線(xiàn)程是鎖持有者,則計(jì)數(shù)器減1,如果計(jì)數(shù)器為0則釋放鎖,如果當(dāng)前線(xiàn)程不是鎖持有者,拋出異常
*/
public void unlock() {
sync.release(1);
}
/**
* 返回用來(lái)與此 Lock 實(shí)例一起使用的 Condition 實(shí)例。
*/
public Condition newCondition() {
return sync.newCondition();
}
/* 刪除了用于 監(jiān)控系統(tǒng),測(cè)試調(diào)試的方法*/
}
我們可以看到內(nèi)部所有的方法都是調(diào)用了內(nèi)部類(lèi) Sync,Sync繼承于AQS(AbstractQueuedSynchronizer ),同時(shí)Sync有兩個(gè)子類(lèi)分別是非公平NonfairSync,和公平FairSync

5.1 模板模式
模板模式(Template Pattern)中,一個(gè)抽象類(lèi)公開(kāi)定義了執(zhí)行它的方法的方式/模板。它的子類(lèi)可以按需要重寫(xiě)方法實(shí)現(xiàn),但調(diào)用將以抽象類(lèi)中定義的方式進(jìn)行。這種類(lèi)型的設(shè)計(jì)模式屬于行為型模式。
根據(jù)定義可以和明顯的看出來(lái) AQS使用了模板模式,
5.2 裝飾器模式
裝飾器模式(Decorator Pattern)允許向一個(gè)現(xiàn)有的對(duì)象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。這種類(lèi)型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類(lèi)的一個(gè)包裝。
這種模式創(chuàng)建了一個(gè)裝飾類(lèi),用來(lái)包裝原有的類(lèi),并在保持類(lèi)方法簽名完整性的前提下,提供了額外的功能。
根據(jù)裝飾器模式的介紹,感覺(jué) ReentrantLock 就像對(duì)Sync的包裝
5.3 策略模式
在策略模式(Strategy Pattern)中,一個(gè)類(lèi)的行為或其算法可以在運(yùn)行時(shí)更改。這種類(lèi)型的設(shè)計(jì)模式屬于行為型模式。
根據(jù)策略模式介紹,ReentrantLock的構(gòu)造器根據(jù)參數(shù)使用了簡(jiǎn)單的策略選擇
以上是對(duì)鎖類(lèi)型,Lock接口,ReentrantLock做了一個(gè)簡(jiǎn)單的介紹,以及個(gè)人對(duì)于設(shè)計(jì)模式的猜想吧,下面將以ReentrantLock.lock(), ReentrantLock.unlock()進(jìn)行一步一步的深入分析源碼,首先讓我們先簡(jiǎn)單的了解下AQS
6. AbstractQueuedSynchronizer(AQS 略講)
官方介紹:
為實(shí)現(xiàn)依賴(lài)于先進(jìn)先出 (FIFO) 等待隊(duì)列的阻塞鎖和相關(guān)同步器(信號(hào)量、事件,等等)提供一個(gè)框架。此類(lèi)的設(shè)計(jì)目標(biāo)是成為依靠單個(gè)原子 int 值來(lái)表示狀態(tài)的大多數(shù)同步器的一個(gè)有用基礎(chǔ)。子類(lèi)必須定義更改此狀態(tài)的受保護(hù)方法,并定義哪種狀態(tài)對(duì)于此對(duì)象意味著被獲取或被釋放。假定這些條件之后,此類(lèi)中的其他方法就可以實(shí)現(xiàn)所有排隊(duì)和阻塞機(jī)制。
- 先進(jìn)先出 (FIFO) 等待隊(duì)列 (通過(guò)字段head,tail來(lái)表示)
- 原子 int 值(volatile int state)
- 需要適當(dāng)?shù)刂匦露x以下方法(以下方法默認(rèn)實(shí)現(xiàn)都是直接拋出異常)
- tryAcquire 試圖在獨(dú)占模式下獲取對(duì)象狀態(tài)。失敗將線(xiàn)程加入隊(duì)列
- tryRelease 試圖設(shè)置狀態(tài)來(lái)反映獨(dú)占模式下的一個(gè)釋放。
- tryAcquireShared 試圖在共享模式下獲取對(duì)象狀態(tài)
- tryReleaseShared 試圖設(shè)置狀態(tài)來(lái)反映共享模式下的一個(gè)釋放。
- isHeldExclusively 如果對(duì)于當(dāng)前線(xiàn)程,同步是以獨(dú)占方式進(jìn)行的,則返回 true
簡(jiǎn)單來(lái)說(shuō),AQS內(nèi)部一共有三個(gè)字段,head和tail構(gòu)造FIFO等待隊(duì)列,state表示狀態(tài),ReentrantLock的內(nèi)部類(lèi)Sync和子類(lèi)就是重寫(xiě)了tryAcquire 和 tryRelease 實(shí)現(xiàn)了鎖
/**
* 等待隊(duì)列的頭部,懶加載初始化,只能通過(guò)setHead修改,如果頭存在,它的等待狀態(tài)是 保證不被取消。
*/
private transient volatile Node head;
/**
* 等待隊(duì)列的尾部,懶加載初始化,只有通過(guò)new 一個(gè)等待node才能修改
*/
private transient volatile Node tail;
/**
* 同步狀態(tài)值
*/
private volatile int state;
6.1 AQS內(nèi)部的node
之所以貼出來(lái)node的代碼,因?yàn)橛袔讉€(gè)狀態(tài)轉(zhuǎn)換,大家可以下面注意下
static final class Node {
/* 標(biāo)識(shí)節(jié)點(diǎn)當(dāng)前在共享模式下 */
static final Node SHARED = new Node();
/** 標(biāo)識(shí)節(jié)點(diǎn)當(dāng)前在獨(dú)占模式下 */
static final Node EXCLUSIVE = null;
/** 因?yàn)槌瑫r(shí)或者中斷,節(jié)點(diǎn)會(huì)被設(shè)置為取消狀態(tài),被取消的節(jié)點(diǎn)時(shí)不會(huì)參與到競(jìng)爭(zhēng)中的,他會(huì)一直保持取消狀態(tài)不會(huì)轉(zhuǎn)變?yōu)槠渌麪顟B(tài); */
static final int CANCELLED = 1;
/**
* 后繼節(jié)點(diǎn)的線(xiàn)程處于等待狀態(tài),而當(dāng)前節(jié)點(diǎn)的線(xiàn)程如果釋放了同步狀態(tài)或者被取消,將會(huì)通知后繼節(jié)點(diǎn),使后繼節(jié)點(diǎn)的線(xiàn)程得以運(yùn)行,
* 在AQS.shouldParkAfterFailedAcquire(pred,node)方法中會(huì)把前驅(qū)節(jié)點(diǎn)的狀態(tài)設(shè)置為此狀態(tài),表示隊(duì)列此節(jié)點(diǎn)后面有線(xiàn)程等待,可以理解為這個(gè)狀態(tài)是后面線(xiàn)程的狀態(tài)
*/
static final int SIGNAL = -1;
/**
* 節(jié)點(diǎn)在等待隊(duì)列中,節(jié)點(diǎn)線(xiàn)程等待在Condition上,當(dāng)其他線(xiàn)程對(duì)Condition調(diào)用了signal()后,改節(jié)點(diǎn)將會(huì)從等待隊(duì)列中轉(zhuǎn)移到同步隊(duì)列中,加入到同步狀態(tài)的獲取中
*/
static final int CONDITION = -2;
/**
* 表示下一次共享式同步狀態(tài)獲取將會(huì)無(wú)條件地傳播下去 表示當(dāng)前場(chǎng)景下后續(xù)的acquireShared能夠得以執(zhí)行
*/
static final int PROPAGATE = -3;
/* 值為0,表示當(dāng)前節(jié)點(diǎn)在sync隊(duì)列中,等待著獲取鎖。 */
volatile int waitStatus;
/** 前驅(qū)節(jié)點(diǎn),比如當(dāng)前節(jié)點(diǎn)被取消,那就需要前驅(qū)節(jié)點(diǎn)和后繼節(jié)點(diǎn)來(lái)完成連接。 */
volatile Node prev;
/** 當(dāng)前節(jié)點(diǎn)點(diǎn)后繼節(jié)點(diǎn) */
volatile Node next;
/** 入隊(duì)列時(shí)的當(dāng)前線(xiàn)程。 */
volatile Thread thread;
/** 存儲(chǔ)condition隊(duì)列中的后繼節(jié)點(diǎn) */
Node nextWaiter;
/**
* 共享模式返回true
*/
final boolean isShared() {
return nextWaiter == SHARED;
}
/**
* 返回前驅(qū)節(jié)點(diǎn)
*/
final Node predecessor() {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { }
Node(Node nextWaiter) {
this.nextWaiter = nextWaiter;
THREAD.set(this, Thread.currentThread());
}
Node(int waitStatus) {
WAITSTATUS.set(this, waitStatus);
THREAD.set(this, Thread.currentThread());
}
}
7. ReentrantLock.lock() (非公平)調(diào)用過(guò)程分析
7.1 線(xiàn)程1第一次調(diào)用
sync 是非公平鎖 NonfairSync extend Sync 的實(shí)例,核心的實(shí)現(xiàn)就是AQS.acquire(1)調(diào)用NonfairSync .tryAcquire(1),調(diào)用方法鏈

- Lock.lock()
直接調(diào)用內(nèi)部類(lèi)Sync的acquire(1),既AQS.acquire(1) ,acquire是sync從AQS繼承來(lái)的public final 方法
- AQS.acquire(1)
acquire直接調(diào)用了tryAcquire(1),此方法是需要子類(lèi)實(shí)現(xiàn),既NonfairSync.tryAcquire(1)
- NonfairSync.tryAcquire(1)
直接調(diào)用了父類(lèi)的Sync.nonfairTryAcquire(1)
- Sync.nonfairTryAcquire(1)
- 獲取同步狀態(tài)值volatile int state;
- state==0 cas比較替換
- 替換成功設(shè)置當(dāng)前線(xiàn)程返回true 獲取鎖成功
public class ReentrantLock implements Lock, java.io.Serializable {
/** 可以看到此方法直接調(diào)用了 AQS的 public final方法 */
public void lock() {
sync.acquire(1);
}
}
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// acquire 直接調(diào)用了 tryAcquire ,tryAcquire是抽象方法需要子類(lèi)NonfairSync 實(shí)現(xiàn), acquireQueued暫時(shí)忽略它, 我們假設(shè)第一次調(diào)用tryAcquire 返回true獲取到鎖
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
}
static final class NonfairSync extends Sync {
// 直接調(diào)用父類(lèi)Sync的非公平nonfairTryAcquire
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
/** */
abstract static class Sync extends AbstractQueuedSynchronizer {
final boolean nonfairTryAcquire(int acquires) {
1、獲取當(dāng)前線(xiàn)程
final Thread current = Thread.currentThread();
2、獲取 AQS volatile state 的狀態(tài)值
int c = getState();
3、狀態(tài)是否等于0 等于說(shuō)明此鎖暫時(shí)無(wú)線(xiàn)程占有
if (c == 0) {
4、樂(lè)觀鎖設(shè)置狀態(tài) 比較替換狀態(tài)值 新的api利用了java9 的句柄替換了Unsafe實(shí)現(xiàn)
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
3.1、進(jìn)入這個(gè)else if分支,說(shuō)明是重入了,需要操作:state=state+1
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
public abstract class AbstractQueuedSynchronizer {
// VarHandle mechanics java9利用句柄 提供了一系列標(biāo)準(zhǔn)的內(nèi)存屏障操作,
// 用于更加細(xì)粒度的控制內(nèi)存排序。在安全性、可用性、性能上都要優(yōu)于現(xiàn)有的API。
// VarHandle 可以與任何字段、數(shù)組元素或靜態(tài)變量關(guān)聯(lián),支持在不同訪(fǎng)問(wèn)模型下對(duì)這些類(lèi)型變量的訪(fǎng)問(wèn),
// 包括簡(jiǎn)單的 read/write 訪(fǎng)問(wèn),volatile 類(lèi)型的 read/write 訪(fǎng)問(wèn),和 CAS(compare-and-swap)等。
private static final VarHandle STATE;
protected final boolean compareAndSetState(int expect, int update) {
return STATE.compareAndSet(this, expect, update);
}
static {
try {
MethodHandles.Lookup l = MethodHandles.lookup();
STATE = l.findVarHandle(AbstractQueuedSynchronizer.class, "state", int.class);
}
}
7.2 線(xiàn)程2調(diào)用lock()
假如線(xiàn)程1和線(xiàn)程2同時(shí)調(diào)用lock()方法,線(xiàn)程1優(yōu)先獲取到鎖,線(xiàn)程2的執(zhí)行方法鏈如下

- Lock.lock() --> AQS.acquire(1) --> NonfairSync.tryAcquire(1) --> Sync.nonfairTryAcquire(1)
他們幾個(gè)方法依次調(diào)用,nonfairTryAcquire方法判斷 state!=0,不是當(dāng)前線(xiàn)程return false,然后AQS.acquire(1) 方繼續(xù)執(zhí)行acquireQueued(addWaiter(Node.EXCLUSIVE)
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
2、addWaiter(Node.EXCLUSIVE)
private Node addWaiter(Node mode) {
Node node2 = new Node(mode); 1、包裝當(dāng)前線(xiàn)程為node2(此處是我改為的node2方便理解)
for (;;) {
Node oldTail = tail; 2、獲取tail
if (oldTail != null) {
node2.setPrevRelaxed(oldTail); 3、設(shè)置node2 的prev指向tail
if (compareAndSetTail(oldTail, node2)) { 4、樂(lè)觀鎖使tail指向node2
oldTail.next = node2; 5、老tail 的next指向node2
return node2;
}
} else {
initializeSyncQueue(); 0、初始化AQS隊(duì)列如下圖
}
}
}
private final void initializeSyncQueue() {
Node h;
if (HEAD.compareAndSet(this, null, (h = new Node())))
tail = h;
}
- 包裝當(dāng)前線(xiàn)程為node(取個(gè)別名為node2)
- 獲取到tail節(jié)點(diǎn)
- 如果tail節(jié)點(diǎn)等于null(因?yàn)槭堑诙€(gè)線(xiàn)程所以此處tail節(jié)點(diǎn)等于null)初始化隊(duì)列

- 循環(huán)再來(lái),如果tail節(jié)點(diǎn)不等于null(上面已經(jīng)初始化)
- 4.1 設(shè)置當(dāng)前線(xiàn)程node2的prev指向tail(head的node1)
- 4.2 樂(lè)觀鎖比較替換node2為tail(既tail指向node2)
- 4.3 老tail(node1)的next指向當(dāng)前node2 返回當(dāng)前node2

3、AQS.acquireQueued(node2, 1)
- 獲取到當(dāng)前node2節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)
- 判斷是head -- return true(此時(shí)線(xiàn)程2上面的情況前驅(qū)節(jié)點(diǎn)是head)
- tryAcquire(1) 嘗試去獲取鎖(假如這個(gè)時(shí)候,線(xiàn)程3來(lái)了獲取到了,或者線(xiàn)程1還沒(méi)執(zhí)行完畢)return false
- 執(zhí)行 shouldParkAfterFailedAcquire(p, node)
final boolean acquireQueued(final Node node, int arg) {
boolean interrupted = false;
try {
for (;;) {
final Node p = node.predecessor(); 1. 獲取到當(dāng)前node2節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)
2. 判斷是head -- return true(此時(shí)線(xiàn)程2上面的情況前驅(qū)節(jié)點(diǎn)是head)
3. tryAcquire(1) 嘗試去獲取鎖(假如這個(gè)時(shí)候,線(xiàn)程3來(lái)了獲取到了,或者線(xiàn)程1還沒(méi)執(zhí)行完畢)return false
if (p == head && tryAcquire(arg)) {
** 假如線(xiàn)程2獲取到鎖,為啥設(shè)置自己為head,
** 因?yàn)榫€(xiàn)程3來(lái)了,他的前驅(qū)節(jié)點(diǎn)是線(xiàn)程2,所以線(xiàn)程2把自己設(shè)置為head,線(xiàn)程3才能進(jìn)入此方法
setHead(node);
p.next = null; // help GC
return interrupted;
}
4. 執(zhí)行 shouldParkAfterFailedAcquire(p, node)
if (shouldParkAfterFailedAcquire(p, node))
interrupted |= parkAndCheckInterrupt();
}
} catch (Throwable t) {
cancelAcquire(node);
if (interrupted)
selfInterrupt();
throw t;
}
}
- shouldParkAfterFailedAcquire 判斷此節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)狀態(tài),因?yàn)榍膀?qū)節(jié)點(diǎn)為head節(jié)點(diǎn),狀態(tài)為0,所以只會(huì)執(zhí)行設(shè)置 前驅(qū)節(jié)點(diǎn)狀態(tài)為 Node.SIGNAL 返回false
- 因?yàn)榉祷豧alse所以再次for循環(huán),假如再次沒(méi)有獲取到鎖,第二次進(jìn)入shouldParkAfterFailedAcquire ,因?yàn)閜rev的狀態(tài)剛剛被設(shè)置為signal,所以返回true
- 所以執(zhí)行 interrupted |= parkAndCheckInterrupt(); 阻塞當(dāng)前線(xiàn)程返回是否中斷
(此處分析的是lock()方法只是返回,lockInterruptibly()會(huì)主動(dòng)拋出 InterruptedException)
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL) // 后繼節(jié)點(diǎn)的線(xiàn)程處于等待狀態(tài),而當(dāng)前節(jié)點(diǎn)的線(xiàn)程如果釋放了同步狀態(tài)或者被取消,將會(huì)通知后繼節(jié)點(diǎn),使后繼節(jié)點(diǎn)的線(xiàn)程得以運(yùn)行
return true;
if (ws > 0) { // 因?yàn)槌瑫r(shí)或者中斷,節(jié)點(diǎn)會(huì)被設(shè)置為取消狀態(tài)
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
*** 設(shè)置前驅(qū)節(jié)點(diǎn) 等待狀態(tài)
pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
}
return false;
}
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
7.3 線(xiàn)程3調(diào)用lock()

假如線(xiàn)程2處于等待狀態(tài),那么線(xiàn)程3會(huì)包裝成node3,在QAS.addWaiter(),會(huì)加入到Node2隊(duì)列后面,然后在AQS.acquireQueued(node,1),會(huì)設(shè)置前驅(qū)節(jié)點(diǎn)狀態(tài)為 Node.SIGNAL阻塞當(dāng)前線(xiàn)程,

8. ReentrantLock.unlock() 調(diào)用過(guò)程分析

1、 ReentrantLock.unlock()直接調(diào)用了 內(nèi)部類(lèi)Sync繼承來(lái)的方法AQS.release(1),
public void unlock() {
sync.release(1);
}
2、AQS.release(1) 調(diào)用子類(lèi)實(shí)現(xiàn)的tryRelease(1)
public final boolean release(int arg) {
1、釋放鎖成功 true
if (tryRelease(arg)) {
Node h = head;
2、我們知道線(xiàn)程2改變了head的狀態(tài)為Node.SIGNAL = -1
if (h != null && h.waitStatus != 0)
unparkSuccessor(h); 3、執(zhí)行unpark
return true;
}
return false;
}
3、Sync.tryRelease(1), 執(zhí)行完畢后回到上一步看注釋
- 獲取狀態(tài)減去1的值
- 如果不是當(dāng)前線(xiàn)程擁有者拋出異常
- 如果值等于0,表示釋放鎖
- 設(shè)置狀態(tài),不使用cas是因?yàn)楫?dāng)前方法必須是在當(dāng)前線(xiàn)程鎖定下調(diào)用的
protected final boolean tryRelease(int releases) {
1、獲取狀態(tài)減去1的值
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
2、如果值等于0,表示釋放鎖
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
3、設(shè)置狀態(tài),不使用cas是因?yàn)楫?dāng)前方法必須是在當(dāng)前線(xiàn)程鎖定下調(diào)用的
setState(c);
return free;
}
4、unparkSuccessor(head)
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
* 如果為負(fù)數(shù),說(shuō)明后繼有等待節(jié)點(diǎn),清理狀態(tài),為啥清理狀態(tài)目前還沒(méi)搞明白
*/
int ws = node.waitStatus;
if (ws < 0)
node.compareAndSetWaitStatus(ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
* 獲取當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn),如果==null,或者>0 節(jié)點(diǎn)取消了
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
從后往前遍歷,找到臨近當(dāng)前節(jié)點(diǎn)的正常狀態(tài)節(jié)點(diǎn)
for (Node p = tail; p != node && p != null; p = p.prev)
if (p.waitStatus <= 0)
s = p;
}
1、喚醒下一個(gè)節(jié)點(diǎn)
if (s != null)
LockSupport.unpark(s.thread);
}
5、for循環(huán)為啥從后往前遍歷
一般不會(huì)出現(xiàn)倒敘全遍歷,因?yàn)槊看喂?jié)點(diǎn)的中斷取消都會(huì)清理一遍
- 我們?cè)诨仡櫹?,addWaite(), 先設(shè)置當(dāng)前node的前驅(qū)節(jié)點(diǎn)為tail
- 然后設(shè)置當(dāng)前節(jié)點(diǎn)為tail,
這樣在上面遍歷的時(shí)候,可以保證一旦節(jié)點(diǎn)加入到隊(duì)列,可以立馬獲取遍歷到他,如果是從前往后遍歷,這邊加入隊(duì)列的時(shí)候,先設(shè)置tail(已經(jīng)成功加入隊(duì)列),然后設(shè)置next,會(huì)出現(xiàn)并發(fā)問(wèn)題,可能遍歷不到最后一個(gè)新加入的節(jié)點(diǎn)
private Node addWaiter(Node mode) {
Node node2 = new Node(mode); 1、包裝當(dāng)前線(xiàn)程為node2(此處是我改為的node2方便理解)
for (;;) {
Node oldTail = tail; 2、獲取tail
if (oldTail != null) {
node2.setPrevRelaxed(oldTail); 3、設(shè)置node2 的prev指向tail
if (compareAndSetTail(oldTail, node2)) { 4、樂(lè)觀鎖使tail指向node2
oldTail.next = node2; 5、老tail 的next指向node2
return node2;
}
} else {
initializeSyncQueue(); 0、初始化AQS隊(duì)列如下圖
}
}
}
6、如果線(xiàn)程2剛剛加入到隊(duì)列還沒(méi)調(diào)用LockSupport.park(this);,而線(xiàn)程1正好執(zhí)行完畢,優(yōu)先調(diào)用了線(xiàn)程2的unpark(),LockSupport.unpark(s.thread);
LockSupport 類(lèi)似于信號(hào)量Semaphore,如果在park之前調(diào)用了unpark,那么再調(diào)用park的時(shí)候不會(huì)阻塞,直接返回
9. 公平鎖
我們可以看到公平鎖在獲取鎖的過(guò)程中,比非公平鎖多了一個(gè)條件,hasQueuedPredecessors()判斷隊(duì)列中是否存在等待節(jié)點(diǎn),jdk10公平鎖,非公平鎖就這一點(diǎn)區(qū)別,和jdk8還是不太一樣的
static final class FairSync extends Sync {
@ReservedStackAccess
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
1、注意這里的 hasQueuedPredecessors()
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
// h !=t 說(shuō)明隊(duì)列不為空
// (s = h.next) == null 不知道在什么情況下 h.next==null
// s.thread != Thread.currentThread() 如果有而且不能是當(dāng)前線(xiàn)程
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
9. 總結(jié)
本篇文章主要是介紹了,可重入鎖ReentrantLock的lock和unlock過(guò)程,至于ReentrantLock中的其他方法lockInterruptibly(),tryLock(),tryLock(long time, TimeUnit unit)就不做過(guò)多的啰嗦了,幾乎都是沒(méi)有什么差別的。下篇文章會(huì)對(duì)Condition做一個(gè)詳細(xì)的解讀
番外篇
1. Java鎖保證可見(jiàn)性的具體實(shí)現(xiàn)
Happens-before規(guī)則
- 從JDK 5開(kāi)始,JSR-133定義了新的內(nèi)存模型,內(nèi)存模型描述了多線(xiàn)程代碼中的哪些行為是合法的,以及線(xiàn)程間如何通過(guò)內(nèi)存進(jìn)行交互。
- 新的內(nèi)存模型語(yǔ)義在內(nèi)存操作(讀取字段,寫(xiě)入字段,加鎖,解鎖)和其他線(xiàn)程操作上創(chuàng)建了一些偏序規(guī)則,這些規(guī)則又叫作Happens-before規(guī)則。
- 它的含義是當(dāng)一個(gè)動(dòng)作happens before另一個(gè)動(dòng)作,這意味著第一個(gè)動(dòng)作被保證在第二個(gè)動(dòng)作之前被執(zhí)行并且結(jié)果對(duì)其可見(jiàn)。我們利用Happens-before規(guī)則來(lái)解釋Java鎖到底如何保證了可見(jiàn)性。
Java內(nèi)存模型一共定義了八條Happens-before規(guī)則,和Java鎖相關(guān)的有以下兩條:
- 內(nèi)置鎖(synchronized)的釋放鎖操作發(fā)生在該鎖隨后的加鎖操作之前
- 一個(gè)volatile變量的寫(xiě)操作發(fā)生在這個(gè)volatile變量隨后的讀操作之前
2. 鎖釋放和獲取的內(nèi)存語(yǔ)義
- 當(dāng)線(xiàn)程釋放鎖時(shí),JMM會(huì)把該線(xiàn)程對(duì)應(yīng)的本地內(nèi)存中的共享變量刷新到主內(nèi)存中
- 當(dāng)線(xiàn)程獲取鎖時(shí),JMM會(huì)把該線(xiàn)程對(duì)應(yīng)的本地內(nèi)存置為無(wú)效。從而使得被監(jiān)視器保護(hù)的臨界區(qū)代碼必須要從主內(nèi)存中去讀取共享變量
鎖釋放與volatile寫(xiě)有相同的內(nèi)存語(yǔ)義;鎖獲取與volatile讀有相同的內(nèi)存語(yǔ)義。
3. 下面對(duì)鎖釋放和鎖獲取的內(nèi)存語(yǔ)義做個(gè)總結(jié):
- 線(xiàn)程A釋放一個(gè)鎖,實(shí)質(zhì)上是線(xiàn)程A向接下來(lái)將要獲取這個(gè)鎖的某個(gè)線(xiàn)程發(fā)出了(線(xiàn)程A對(duì)共享變量所做修改的)消息。
- 線(xiàn)程B獲取一個(gè)鎖,實(shí)質(zhì)上是線(xiàn)程B接收了之前某個(gè)線(xiàn)程發(fā)出的(在釋放這個(gè)鎖之前對(duì)共享變量所做修改的)消息。
- 線(xiàn)程A釋放鎖,隨后線(xiàn)程B獲取這個(gè)鎖,這個(gè)過(guò)程實(shí)質(zhì)上是線(xiàn)程A通過(guò)主內(nèi)存向線(xiàn)程B發(fā)送消息。
4. Lock與synchronized的區(qū)別:
- Lock是一個(gè)接口,是代碼層面的實(shí)現(xiàn);synchronized是關(guān)鍵字,是內(nèi)置的語(yǔ)言實(shí)現(xiàn)(JVM層面)。
- Lock是顯示地獲取釋放鎖,擴(kuò)展性更強(qiáng);synchronized是隱式地獲取釋放鎖,更簡(jiǎn)捷。
- Lock在發(fā)生異常時(shí),如果沒(méi)有主動(dòng)通過(guò)unlock()去釋放鎖,則很可能造成死鎖現(xiàn)象,因此使用Lock時(shí)需要在finally塊中釋放鎖;synchronized在發(fā)生異常時(shí),會(huì)自動(dòng)釋放線(xiàn)程占有的鎖,因此不會(huì)導(dǎo)致死鎖現(xiàn)象發(fā)生。
- Lock可以讓等待鎖的線(xiàn)程響應(yīng)中斷;而使用synchronized時(shí)等待鎖的線(xiàn)程會(huì)一直等待下去,不能響應(yīng)中斷;
- Lock可以嘗試非阻塞、可中斷、超時(shí)地獲取鎖;synchronized不可以。
- Lock可以知道是否成功獲取鎖;synchronized無(wú)法知道。