前面我們學習了ReentrantLock苇侵,其底層就是用了AQS實現(xiàn)的庆聘,應該先講這一章節(jié),但是當時給忘了,現(xiàn)在給補上吧奴艾。
關于ReentrantLock的學習肌厨,可以參考:http://www.reibang.com/p/edec5185196d
AbstractQueuedSynchronizer是阻塞式鎖脸哀,以及同步器組件的實現(xiàn)框架每篷。是JDK中實現(xiàn)并發(fā)編程的核心,它提供了一個基于FIFO隊列镐牺,平時我們工作中經(jīng)常用到的ReentrantLock炫掐,CountDownLatch等都是基于它來實現(xiàn)的。
一睬涧、初識AQS
首先我們還是從前面學習的ReentrantLock入手募胃,看看其代碼結構是什么樣的:
從上圖可以看到以下幾點:
- ReentrantLock實現(xiàn)接口Lock(抽象接口)
- ReentrantLock有三個內(nèi)部類,分別是FrairSync畦浓、NonfairSync痹束、Sync,且FrairSync讶请、NonfairSync繼承自Sync祷嘶。
- Sync繼承AbstractQueuedSynchronizer
- AbstractQueuedSynchronizer有兩個內(nèi)部類,分別是Node、ConditionObject论巍。
- AbstractQueuedSynchronizer繼承自AbstractOwnableSynchronizer(抽象類烛谊,提供獨占線程的get和set)。
AQS有如下的特點:
-
用 state 屬性來表示資源的狀態(tài)嘉汰,包含獨占狀態(tài)和共享狀態(tài)丹禀,對應公平鎖和非公平鎖。子類需要定義如何維護這個狀態(tài)鞋怀,控制如何獲取鎖和釋放鎖双泪,如上面圖中的關系,公平鎖和非公平鎖需要各自去維護這個state密似,達到獲取和釋放鎖的目的攒读。
- getState - 獲取 state 狀態(tài)
- setState - 設置 state 狀態(tài)
- compareAndSetState - 使用CAS設置狀態(tài)
- 獨占模式:只有一個線程能夠訪問資源
- 共享模式:允許多個線程訪問資源
提供了基于 FIFO 的等待隊列,類似于前面講Synchronized原理提到的 Monitor 的 EntryList
使用條件變量來實現(xiàn)等待隊列辛友、線程喚醒機制,同時支持多個條件變量剪返,類似于前面講Synchronized原理提到的 Monitor 的 WaitSet
【公平鎖】與【非公平鎖】:二者的區(qū)別主要在于獲取鎖是否和排隊順序有關废累。當鎖唄一個線程持有,其他嘗試獲取鎖的線程會被掛起脱盲,加到等待隊列中邑滨,先被掛起的在隊列的最前端。當鎖被釋放钱反,需要通知隊列中的線程掖看。作為公平鎖,會先喚醒隊列最前端的線程面哥;而非公平鎖會喚醒所有線程哎壳,通過競爭去獲取鎖,后來的線程有可能獲得鎖尚卫。
二归榕、 源碼分析
下面我們通過源碼剖析其本質(zhì)是什么樣的。
首先在腦海中有個印象吱涉,AQS維護了兩個對個隊列刹泄,一個是同步隊列,一個是阻塞隊列怎爵。
Node可以說是【同步隊列】和【阻塞隊列】的節(jié)點特石。
2.1 Node源碼剖析
static final class Node {
// 模式,分為共享與獨占
// 共享模式
static final Node SHARED = new Node();
// 獨占模式
static final Node EXCLUSIVE = null;
// 結點狀態(tài)
// CANCELLED鳖链,值為1姆蘸,表示當前的線程被取消
// SIGNAL,值為-1,表示當前節(jié)點的后繼節(jié)點包含的線程需要運行乞旦,也就是unpark
// CONDITION贼穆,值為-2,表示當前節(jié)點在等待condition兰粉,也就是在condition隊列中
// PROPAGATE故痊,值為-3,表示當前場景下后續(xù)的acquireShared能夠得以執(zhí)行
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
// 結點狀態(tài)
volatile int waitStatus;
// 前驅(qū)結點
volatile Node prev;
// 后繼結點
volatile Node next;
// 結點所對應的線程
volatile Thread thread;
// 下一個等待者
Node nextWaiter;
// 結點是否在共享模式下等待
final boolean isShared() {
return nextWaiter == SHARED;
}
// 獲取前驅(qū)結點玖姑,若前驅(qū)結點為空愕秫,拋出異常
final Node predecessor() throws NullPointerException {
// 保存前驅(qū)結點
Node p = prev;
if (p == null) // 前驅(qū)結點為空,拋出異常
throw new NullPointerException();
else // 前驅(qū)結點不為空焰络,返回
return p;
}
// 無參構造函數(shù)
Node() { // Used to establish initial head or SHARED marker
}
// 構造函數(shù)戴甩,被addWaiter使用
Node(Thread thread, Node mode) { // Used by addWaiter
this.nextWaiter = mode;
this.thread = thread;
}
// 構造函數(shù)
Node(Thread thread, int waitStatus) { // Used by Condition
this.waitStatus = waitStatus;
this.thread = thread;
}
}
2.2 ConditionObject源碼剖析
實現(xiàn)了condition接口,關于condition的學習后面會介紹闪彼,在學習ReentrantLock時也介紹了其使用方式甜孤。
代碼較多,直接從上向下看吧:
// 內(nèi)部類
public class ConditionObject implements Condition, java.io.Serializable {
// 版本號
private static final long serialVersionUID = 1173984872572414699L;
// condition隊列的頭結點
private transient Node firstWaiter;
// condition隊列的尾結點
private transient Node lastWaiter;
/**
* 構造函數(shù)
*/
public ConditionObject() { }
/**
* 添加新的waiter到wait隊列
*/
private Node addConditionWaiter() {
// 定義尾結點是t
Node t = lastWaiter;
// 尾結點不為空畏腕,并且尾結點的狀態(tài)不為CONDITION(默認是-2缴川,表示當前節(jié)點在conditionObject等待隊列中)
if (t != null && t.waitStatus != Node.CONDITION) {
// 清除狀態(tài)不為CONDITION的結點,對firstWaiter和lastWaiter重新賦值
unlinkCancelledWaiters();
// 將最后一個結點重新賦值給t
t = lastWaiter;
}
// 新建一個結點
Node node = new Node(Thread.currentThread(), Node.CONDITION);
// 尾結點為空
if (t == null)
// 設置condition隊列的頭結點
firstWaiter = node;
else
// 設置為節(jié)點的nextWaiter域為node結點
t.nextWaiter = node;
// 更新condition隊列的尾結點
lastWaiter = node;
return node;
}
/**
* 移除或轉(zhuǎn)移頭結點到sync隊列描馅,直到?jīng)]有取消的或者空為止
*/
private void doSignal(Node first) {
// 循環(huán)
do {
// 將下一個節(jié)點設為首節(jié)點把夸,如果為空
if ( (firstWaiter = first.nextWaiter) == null)
// 設置尾結點為空
lastWaiter = null;
// 設置first結點的nextWaiter域
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null); // 將結點從condition隊列轉(zhuǎn)移到sync隊列失敗并且condition隊列中的頭結點不為空,一直循環(huán)
}
/**
* 轉(zhuǎn)移所有等待隊列的節(jié)點到同步隊列
*/
private void doSignalAll(Node first) {
// condition隊列的頭結點尾結點都設置為空
lastWaiter = firstWaiter = null;
// 循環(huán)
do {
// 獲取first結點的nextWaiter域結點
Node next = first.nextWaiter;
// 設置first結點的nextWaiter域為空
first.nextWaiter = null;
// 將first結點從condition隊列轉(zhuǎn)移到sync隊列
transferForSignal(first);
// 重新設置first
first = next;
} while (first != null);
}
/**
* 過濾掉狀態(tài)不為CONDITION的節(jié)點
* 對firstWaiter和lastWaiter重新賦值
**/
private void unlinkCancelledWaiters() {
// 獲取condition隊列頭結點
Node t = firstWaiter;
// 獲取一個尾結點是null
Node trail = null;
while (t != null) {
// 獲取下一個結點
Node next = t.nextWaiter;
// 頭結點的狀態(tài)不為CONDTION狀態(tài)
if (t.waitStatus != Node.CONDITION) {
// 設置t節(jié)點的下一個等待者為空
t.nextWaiter = null;
if (trail == null) // trail為空铭污,首次進來一定為空
// 重新設置condition隊列的頭結點
firstWaiter = next;
else
// 設置trail結點的nextWaiter域為next結點
trail.nextWaiter = next;
if (next == null) // next結點為空
// 設置condition隊列的尾結點
lastWaiter = trail;
}
else // t結點的狀態(tài)為CONDTION狀態(tài)
// 設置trail結點
trail = t;
// 設置t結點
t = next;
}
}
/**
* 實現(xiàn)Condition接口的signal方法
*/
public final void signal() {
if (!isHeldExclusively()) // 不被當前線程獨占恋日,拋出異常
throw new IllegalMonitorStateException();
// 保存condition隊列頭結點
Node first = firstWaiter;
if (first != null) // 頭結點不為空
// 喚醒一個等待線程,將頭結點從阻塞隊列移除嘹狞,添加到同步隊列
doSignal(first);
}
/**
* 實現(xiàn)Condition的signalAll方法岂膳,喚醒所有線程
*/
public final void signalAll() {
if (!isHeldExclusively()) // 不被當前線程獨占,拋出異常
throw new IllegalMonitorStateException();
// 保存condition隊列頭結點
Node first = firstWaiter;
if (first != null) // 頭結點不為空
// 喚醒所有等待線程磅网,將頭結點從阻塞隊列移除闷营,添加到同步隊列
doSignalAll(first);
}
/**
* 與await()區(qū)別在于,使用await方法知市,調(diào)用interrupt()中斷后會報錯傻盟,而該方法不會報錯。
*/
public final void awaitUninterruptibly() {
// 添加一個結點到等待隊列
Node node = addConditionWaiter();
// 獲取釋放的狀態(tài)
int savedState = fullyRelease(node);
boolean interrupted = false;
while (!isOnSyncQueue(node)) { //
// 阻塞當前線程
LockSupport.park(this);
if (Thread.interrupted()) // 當前線程被中斷
// 設置interrupted狀態(tài)
interrupted = true;
}
if (acquireQueued(node, savedState) || interrupted) //
selfInterrupt();
}
/**
* 等待嫂丙,當前線程在接到信號或被中斷之前一直處于等待狀態(tài)
*/
public final void await() throws InterruptedException {
// 當前線程被中斷娘赴,拋出異常
if (Thread.interrupted())
throw new InterruptedException();
// 將當前線程包裝成Node跟啤,尾插入到等待隊列中
Node node = addConditionWaiter();
// 釋放當前線程所占用的lock诽表,在釋放的過程中會喚醒同步隊列中的下一個節(jié)點
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
// 當前線程進入到等待狀態(tài)
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) // 檢查結點等待時的中斷類型
break;
}
// 自旋等待獲取到同步狀態(tài)(即獲取到lock)
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
// 處理被中斷的情況
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
/**
* 等待唉锌,當前線程在接到信號、被中斷或到達指定等待時間之前一直處于等待狀態(tài)
*/
public final long awaitNanos(long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
transferAfterCancelledWait(node);
break;
}
if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
nanosTimeout = deadline - System.nanoTime();
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return deadline - System.nanoTime();
}
/**
* 等待竿奏,當前線程在接到信號袄简、被中斷或到達指定最后期限之前一直處于等待狀態(tài)
*/
public final boolean awaitUntil(Date deadline)
throws InterruptedException {
long abstime = deadline.getTime();
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (System.currentTimeMillis() > abstime) {
timedout = transferAfterCancelledWait(node);
break;
}
LockSupport.parkUntil(this, abstime);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
/**
* 等待,當前線程在接到信號泛啸、被中斷或到達指定等待時間之前一直處于等待狀態(tài)绿语。此方法在行為上等
* 效于:awaitNanos(unit.toNanos(time)) > 0
*/
public final boolean await(long time, TimeUnit unit)
throws InterruptedException {
long nanosTimeout = unit.toNanos(time);
if (Thread.interrupted())
throw new InterruptedException();
// 1. 將當前線程包裝成Node,尾插入到等待隊列中
Node node = addConditionWaiter();
// 2. 釋放當前線程所占用的lock候址,在釋放的過程中會喚醒同步隊列中的下一個節(jié)點
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
timedout = transferAfterCancelledWait(node);
break;
}
if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
nanosTimeout = deadline - System.nanoTime();
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
2.3 鎖的獲取和釋放
整個AQS的設計理念就是通過state字段來實現(xiàn)鎖的獲取和釋放吕粹,鎖有主要分為公平鎖和非公平鎖。
2.3.1 公平鎖
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
// 繼承自AQS的方法岗仑,內(nèi)部先調(diào)用tryAcquire獲取鎖匹耕,獲取失敗則添加下城到等待隊列當中
acquire(1);
}
/**
* 公平鎖版本的tryAcquire
*/
protected final boolean tryAcquire(int acquires) {
// 獲取當前線程
final Thread current = Thread.currentThread();
// 獲取鎖的狀態(tài)
int c = getState();
// 0表示鎖沒有被持有
if (c == 0) {
// 判斷當前等待隊列是否有節(jié)點在等待,沒有才去競爭
if (!hasQueuedPredecessors() &&
// 比較并替換狀態(tài)
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;
}
}
2.3.2 非公平鎖
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* 立即獲取鎖荠雕,失敗會加入等待隊列
*/
final void lock() {
// 通過CAS嘗試獲取鎖稳其,成功則設置當前線程獨占
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
// 否則加入等待隊列·····································································································································
acquire(1);
}
/**
* 非公平鎖版本的tryAcquire
*/
protected final boolean tryAcquire(int acquires) {
// 走其父類Sync的默認nonfairTryAcquire
return nonfairTryAcquire(acquires);
}
}
2.3.3 Syc子類
這是公平鎖和非公平鎖的父類,提供統(tǒng)一的tryRelease方法釋放鎖
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* 提供非公平版本的快捷路徑
*/
abstract void lock();
/**
* 非公平鎖獲取炸卑,默認就是非公平鎖
*/
final boolean nonfairTryAcquire(int acquires) {
// 獲取當前線程
final Thread current = Thread.currentThread();
// 獲取當前鎖的狀態(tài)
int c = getState();
// 0表示沒有被占用
if (c == 0) {
// CAS占用既鞠,成功則設置當前線程為獨占鎖
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 當前線程是獨占鎖,表示鎖重入
else if (current == getExclusiveOwnerThread()) {
// 狀態(tài) + 1
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
// 設置當前狀態(tài)
setState(nextc);
return true;
}
return false;
}
/**
* 釋放鎖
*/
protected final boolean tryRelease(int releases) {
// 當前狀態(tài) 減去 釋放的數(shù)量
int c = getState() - releases;
// 如果當前線程不是占有鎖的線程矾兜,拋出異常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 當全部釋放后,狀態(tài)為0患久,取消獨占線程
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
// 設置狀態(tài)為0椅寺,返回釋放成功
setState(c);
return free;
}
protected final boolean isHeldExclusively() {
// 當前線程是否是鎖持有者
return getExclusiveOwnerThread() == Thread.currentThread();
}
// 獲取當前持有者
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
// 獲取持有數(shù),只有是線程持有者才能獲取
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
}
3.3.4 acquire 和 release
在AQS當中還有兩個核心方法:
- acquire():獲取鎖蒋失,這是實際鎖調(diào)用上鎖的真正方法返帕,前面的try開頭的知識嘗試獲取鎖,即使失敗也不會添加到等待隊列篙挽。
public final void acquire(int arg) {
// 嘗試獲取
if (!tryAcquire(arg) &&
// 嘗試獲取成功荆萤,以獨占方式添加到等待隊列,并不斷地嘗試占有鎖知道成功
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
- release():釋放鎖铣卡,這是實際釋放鎖的方法链韭,會調(diào)用鎖自定義的同步器實現(xiàn)的tryRelease方法:
/** * 嘗試釋放,成功后返回true */ public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
后面我們自定義不可重入鎖煮落,來看看同步器和鎖的關系是什么樣的敞峭,加深理解。
2.4 簡單總結
到此為止蝉仇,通過閱讀前面的源碼內(nèi)容旋讹,我們可以有如下的總結:
- 鎖的釋放和獲取都是圍繞 【state】來做的殖蚕,0表示未持有鎖,1表示獨占沉迹,大于一表示鎖重入
- 獲取鎖的姿勢如下:
// 如果獲取鎖失敗 if (!tryAcquire(arg)) { // 入隊, 可以選擇阻塞當前線程 park unpark }
- 釋放鎖的姿勢如下:
// 如果獲取鎖成功 if (!tryRelease(arg)) { // 讓阻塞線程恢復運行 }
三睦疫、實踐
了解了AQS的結構之后,我們不妨自己動手實踐一番鞭呕。加深理解蛤育。
定義一個不可重入鎖,需要一個同步器琅拌,一個鎖缨伊,一個測試類
自定義同步器:
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
/**
* @description: 實現(xiàn)一個不可重入鎖 同步器,state最大只能是1
* @author:weirx
* @date:2022/1/13 13:49
* @version:3.0
*/
public class MyLockSynchronizer extends AbstractQueuedSynchronizer {
@Override
protected boolean tryAcquire(int acquires) {
int state = getState();
if (state == 0) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
}
return false;
}
@Override
protected boolean tryRelease(int acquires) {
int c = getState() - acquires;
if (c == 0) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
return false;
}
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
protected ConditionObject newCondition() {
return new ConditionObject();
}
}
自定義鎖:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* @description: 自定義鎖
* @author:weirx
* @date:2022/1/13 14:05
* @version:3.0
*/
public class MyLock implements Lock {
MyLockSynchronizer myLockSynchronizer = new MyLockSynchronizer();
@Override
public void lock() {
// 嘗試獲取鎖进宝,失敗則加入等待隊列
myLockSynchronizer.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
// 嘗試獲取鎖刻坊,失敗則加入等待隊列, 可中斷
myLockSynchronizer.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
// 嘗試獲取鎖,不加入等待隊列
return myLockSynchronizer.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
// 嘗試獲取鎖党晋,不加入等待隊列,有實現(xiàn)
return myLockSynchronizer.tryAcquireNanos(1, unit.toNanos(time));
}
@Override
public void unlock() {
// 釋放鎖
myLockSynchronizer.release(1);
}
@Override
public Condition newCondition() {
// 條件變量
return myLockSynchronizer.newCondition();
}
}
測試鎖的效果:
/**
* @description: 測試
* @author:weirx
* @date:2022/1/13 14:24
* @version:3.0
*/
public class TestMyLock {
public static void main(String[] args) {
MyLock myLock = new MyLock();
new Thread(() -> {
try {
myLock.lock();
System.out.println(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")
+ " " + Thread.currentThread().getName() + " :acquire lock success");
// 休眠一秒看效果
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
myLock.unlock();
System.out.println(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")
+ " " + Thread.currentThread().getName() + " :release lock success");
}
}, "t1").start();
new Thread(() -> {
try {
myLock.lock();
System.out.println(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")
+ " " + Thread.currentThread().getName() + " :acquire lock success");
} finally {
myLock.unlock();
System.out.println(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss")
+ " " + Thread.currentThread().getName() + " :release lock success");
}
}, "t2").start();
}
}
結果谭胚,ti一秒后釋放鎖,才會由t2獲得鎖:
2022-01-13 14:34:56 t1 :acquire lock success
2022-01-13 14:34:57 t2 :acquire lock success
2022-01-13 14:34:57 t1 :release lock success
2022-01-13 14:34:57 t2 :release lock success
測試下不可重入是否好使未玻,只需要在上述測試代碼的線程t1中灾而,再次使用myLock.lock()獲取一次鎖,發(fā)現(xiàn)扳剿,整個程序被卡住了旁趟,只會打印一條信息:
2022-01-13 14:35:56 t1 :acquire lock success
四、關于Condition的補充
本篇沒有介紹Condition的具體內(nèi)容庇绽,但是在之前講解ReentrantLock提到過【條件變量】锡搜,可以返回去看這篇文章了解其用法:http://www.reibang.com/p/edec5185196d
源碼學習真是難,看別人說的再多不如自己跟著走一遍瞧掺,建議同學們參照本文自己跟蹤一遍耕餐。