上一章詳細(xì)介紹了AQS的源碼粒竖,這一章我們來分析JUC框架中最常用的鎖ReentrantLock(可重入獨占鎖土铺,也叫可重入互斥鎖)
public class ReentrantLock implements Lock, java.io.Serializable {}
ReentrantLock實現(xiàn)Lock接口,以及Serializable可序列化接口。
可重入獨占鎖的意思:
- 同一時間只能有一個線程持有這個鎖。
- 持有這個鎖的線程可以再次進(jìn)入另一個被這個鎖鎖住的模塊诈火,即持有這個鎖的線程可以重復(fù)獲取鎖。
一. Lock接口
package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
public interface Lock {
// 獲取鎖状答,如果獲取不到冷守,就一直等待刀崖。不響應(yīng)中斷請求
void lock();
// 獲取鎖,如果獲取不到教沾,就一直等待蒲跨。如果在線程等待期間有中斷請求就拋出異常
void lockInterruptibly() throws InterruptedException;
// 嘗試用非公平鎖方式去獲取鎖译断,立即返回授翻。返回true表示獲取成功,返回false表示獲取失敗
boolean tryLock();
// 在規(guī)定的unit時間內(nèi)獲取鎖孙咪,如果時間到了還沒有獲取到鎖堪唐,則返回false,表示獲取失敗
// 如果在線程等待期間有中斷請求就拋出異常
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
// 當(dāng)前線程釋放占用的鎖翎蹈,并喚醒這個鎖上的一個等待線程
void unlock();
// 創(chuàng)建一個Condition對象
Condition newCondition();
}
這個接口提供獲取鎖淮菠,釋放鎖以及生成Condition對象的方法。
二. 構(gòu)造函數(shù)和成員屬性
2.1 成員屬性
// ReentrantLock通過sync變量荤堪,實現(xiàn)獨占鎖的操作合陵。
//Sync是AbstractQueuedSynchronizer的子類
private final Sync sync;
ReentrantLock只有這一個成員變量,它是AQS的子類澄阳,所以可以通過sync實現(xiàn)獨占鎖的操作拥知。
2.2 構(gòu)造函數(shù)
// 默認(rèn)創(chuàng)建的是非公平鎖
public ReentrantLock() {
sync = new NonfairSync();
}
// 根據(jù)fair值,決定創(chuàng)建公平鎖還是非公平鎖
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
根據(jù)參數(shù)fair來決定是公平鎖還是非公平鎖碎赢,默認(rèn)是非公平鎖低剔。
三. Sync內(nèi)部類
這個類也是個抽樣類,它的兩個子類就是FairSync和NonfairSync肮塞。有兩個重要方法襟齿。
3.1 nonfairTryAcquire方法
使用非公平方式去嘗試獲取鎖
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// 獲取鎖的記錄狀態(tài)state
int c = getState();
// 如果c==0表示當(dāng)前鎖是空閑的
if (c == 0) {
// 通過CAS原子操作方式設(shè)置鎖的狀態(tài),如果為true枕赵,表示當(dāng)前線程獲取的鎖猜欺,
// 為false,鎖的狀態(tài)被其他線程更改拷窜,當(dāng)前線程獲取的鎖失敗
if (compareAndSetState(0, acquires)) {
// 設(shè)置當(dāng)前線程為獨占鎖的線程
setExclusiveOwnerThread(current);
return true;
}
}
// 判斷當(dāng)前線程是不是獨占鎖的線程
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
// 更改鎖的記錄狀態(tài)
setState(nextc);
return true;
}
return false;
}
方法流程:
- 調(diào)用getState方法獲取鎖的記錄狀態(tài)c
- 如果c==0表示當(dāng)前鎖是空閑的开皿。因為是非公平的方法獲取鎖,所以直接調(diào)用compareAndSetState更改鎖的狀態(tài)装黑,如果成功副瀑,表示當(dāng)前線程獲取了鎖,如果失敗恋谭,表示鎖的狀態(tài)別的線程更改了糠睡,當(dāng)前線程獲取鎖失敗。
- 如果c不等于0疚颊,那么要看當(dāng)前線程是不是獲取鎖的線程狈孔,因為ReentrantLock是可重入鎖信认,獲取鎖的線程可以重復(fù)獲取鎖。
3.2 tryRelease方法
嘗試釋放鎖資源均抽,返回true表示完全釋放了鎖資源嫁赏,返回false表示還持有鎖資源。
因為鎖是可重入的油挥,所以鎖可能要釋放多次潦蝇。
protected final boolean tryRelease(int releases) {
// c表示新的鎖的記錄狀態(tài)
int c = getState() - releases;
// 如果當(dāng)前線程不是獨占鎖的線程,就拋出IllegalMonitorStateException異常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
// 標(biāo)志是否可以釋放鎖
boolean free = false;
// 當(dāng)新的鎖的記錄狀態(tài)為0時深寥,表示可以釋放鎖
if (c == 0) {
free = true;
// 設(shè)置獨占鎖的線程為null
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
方法流程:
- 先計算新的鎖的記錄狀態(tài)c攘乒。
- 如果當(dāng)前線程不是獨占鎖的線程,就拋出IllegalMonitorStateException異常惋鹅。
- 當(dāng)新的鎖的記錄狀態(tài)為0時则酝,表示完全釋放鎖資源,就喚醒另一個等待鎖的線程了闰集。
- 設(shè)置新的鎖的記錄狀態(tài)沽讹。
四. NonfairSync 非公平鎖
/**
* 非公平鎖
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
// 獲取鎖,如果沒有獲取到鎖武鲁,則當(dāng)前線程要阻塞等待
final void lock() {
// compareAndSetState返回true爽雄,表示當(dāng)前線程獲取鎖成功。
// 因為是非公平鎖洞坑,所以不需要判斷AbstractQueuedSynchronizer線程等待隊列是否有值
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
// 調(diào)用acquire方法盲链,獲取鎖
acquire(1);
}
// 嘗試獲取鎖,獲取到鎖返回true迟杂,沒有獲取到返回false
protected final boolean tryAcquire(int acquires) {
// 調(diào)用父類的nonfairTryAcquire方法
return nonfairTryAcquire(acquires);
}
}
繼承Sync類需要復(fù)寫兩個方法:
- lock獲取鎖的方法刽沾。 因為是非公平鎖方式獲取鎖,所以先直接調(diào)用compareAndSetState方法排拷,如果返回true侧漓,表示鎖資源被當(dāng)前線程持有了。返回false表示鎖的狀態(tài)state不是0监氢,鎖資源已經(jīng)被持有了布蔗。則調(diào)用acquire方法,再次獲取鎖浪腐,不成功就阻塞當(dāng)前線程纵揍。
- tryAcquire方法:嘗試獲取鎖,獲取到鎖返回true议街,沒有獲取到返回false泽谨。這里調(diào)用父類的nonfairTryAcquire方法
五. FairSync 公平鎖
/**
* 公平鎖
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
// 與非公平鎖不同,因為它要考慮線程等待隊列是否有值
acquire(1);
}
// 嘗試獲取鎖,與與非公平鎖最大的不同就是調(diào)用hasQueuedPredecessors()方法
// hasQueuedPredecessors方法返回true吧雹,表示等待線程隊列中有一個線程在當(dāng)前線程之前骨杂,
// 根據(jù)公平鎖的規(guī)則,當(dāng)前線程不能獲取鎖雄卷。
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// 獲取鎖的記錄狀態(tài)
int c = getState();
// 如果c==0表示當(dāng)前鎖是空閑的
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 判斷當(dāng)前線程是不是獨占鎖的線程
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
// 更改鎖的記錄狀態(tài)
setState(nextc);
return true;
}
return false;
}
}
lock 方法:與非公平鎖相比搓蚪,它直接調(diào)用acquire方法,因為是公平鎖丁鹉,所以必須考慮當(dāng)前線程是不是CLH隊列中第一個(即隊列中第一個等待線程)
tryAcquire 方法:與非公平鎖相比妒潭,會調(diào)用調(diào)用hasQueuedPredecessors()方法。 hasQueuedPredecessors方法返回true鳄炉,表示等待線程隊列中有一個線程在當(dāng)前線程之前杜耙,根據(jù)公平鎖的規(guī)則搜骡,當(dāng)前線程不能獲取鎖拂盯。
示例
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
public static void newThread(Lock lock, String name, int time) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("線程"+Thread.currentThread().getName()+" 開始運行,準(zhǔn)備獲取鎖");
lock.lock();
try {
System.out.println("====線程"+Thread.currentThread().getName()+" 在run方法中獲取了鎖");
lockAgain();
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
System.out.println("----線程"+Thread.currentThread().getName()+" 在run方法中釋放了鎖");
lock.unlock();
}
}
private void lockAgain() {
lock.lock();
try {
System.out.println("====線程"+Thread.currentThread().getName()+" 在lockAgain方法中再次獲取了鎖");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
System.out.println("----線程"+Thread.currentThread().getName()+" 在lockAgain方法中釋放了鎖");
lock.unlock();
}
}
},name).start();
}
public static void main(String[] args) {
Lock lock = new ReentrantLock();
newThread(lock, "t1111", 1000);
newThread(lock, "t2222", 1000);
newThread(lock, "t3333", 1000);
}
}
從這個例子中可以看出ReentrantLock是一個可重入鎖记靡,當(dāng)前持有鎖的線程可以進(jìn)入另一個被鎖住的模塊谈竿,而且只有都釋放完成之后,它才會去喚醒一個等待鎖的線程摸吠。
注意一個有趣點空凸,雖然我們創(chuàng)建的非公平鎖,但是每次釋放鎖完成后寸痢,去喚醒一個等待線程時呀洲,你會發(fā)現(xiàn)它一定是等待線程中的第一個線程。那么不是和非公平鎖定義好像不一樣啊啼止。
其實非公平鎖和公平鎖最大的區(qū)別是道逗,當(dāng)鎖是空閑的即沒有任何線程持有鎖,非公平鎖就允許當(dāng)前線程直接獲取鎖献烦,而不用考慮是否有其他線程已經(jīng)在等待這把鎖了滓窍。而公平鎖不是這樣,如果有等待線程隊列巩那,那么就將當(dāng)前線程插入到等待線程隊列尾吏夯。
輸出結(jié)果是
線程t1111 開始運行,準(zhǔn)備獲取鎖
====線程t1111 在run方法中獲取了鎖
====線程t1111 在lockAgain方法中再次獲取了鎖
線程t2222 開始運行即横,準(zhǔn)備獲取鎖
線程t3333 開始運行噪生,準(zhǔn)備獲取鎖
----線程t1111 在lockAgain方法中釋放了鎖
----線程t1111 在run方法中釋放了鎖
====線程t2222 在run方法中獲取了鎖
====線程t2222 在lockAgain方法中再次獲取了鎖
----線程t2222 在lockAgain方法中釋放了鎖
----線程t2222 在run方法中釋放了鎖
====線程t3333 在run方法中獲取了鎖
====線程t3333 在lockAgain方法中再次獲取了鎖
----線程t3333 在lockAgain方法中釋放了鎖
----線程t3333 在run方法中釋放了鎖
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class WaitTest {
private Lock lock;
private Condition condition;
public WaitTest() {
this.lock = new ReentrantLock();
this.condition = this.lock.newCondition();
}
public void waitTest() {
lock.lock();
try {
System.out.println("===線程"+Thread.currentThread().getName()+" 獲取了鎖");
try {
Thread.sleep(1000);
System.out.println("========線程"+Thread.currentThread().getName()+" 調(diào)用await方法 等待并釋放了鎖");
this.condition.await();
System.out.println("========線程"+Thread.currentThread().getName()+" await等待被喚醒");
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
System.out.println("---線程"+Thread.currentThread().getName()+" 釋放鎖");
lock.unlock();
}
}
public void signalTest() {
lock.lock();
try {
System.out.println("===線程"+Thread.currentThread().getName()+" 獲取了鎖");
System.out.println("-------線程"+Thread.currentThread().getName()+" 調(diào)用signal方法");
this.condition.signal();
} finally {
System.out.println("---線程"+Thread.currentThread().getName()+" 釋放鎖");
lock.unlock();
}
}
}
public class LockWaitTest {
public static void newThread(WaitTest waitTest, String name, boolean isWait) {
new Thread(new Runnable() {
@Override
public void run() {
if (isWait) waitTest.waitTest();
else waitTest.signalTest();
}
},name).start();
}
public static void main(String[] args) {
WaitTest waitTest = new WaitTest();
newThread(waitTest, "t1111", true);
newThread(waitTest, "t2222", false);
// newThread(waitTest, "t3333", true);
// newThread(waitTest, "t4444", false);
}
}
輸出結(jié)果是
===線程t1111 獲取了鎖
========線程t1111 調(diào)用await方法 等待并釋放了鎖
===線程t2222 獲取了鎖
-------線程t2222 調(diào)用signal方法
---線程t2222 釋放鎖
========線程t1111 await等待被喚醒
---線程t1111 釋放鎖
附錄
package java.util.concurrent.locks;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
// ReentrantLock通過sync屬性,實現(xiàn)獨占鎖的操作东囚。
// Sync是AbstractQueuedSynchronizer的子類
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
// 加鎖操作跺嗽,又子類具體實現(xiàn)
abstract void lock();
// 非公平狀態(tài)下獲取鎖
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// 獲取鎖的記錄狀態(tài)state
int c = getState();
// 如果c==0表示當(dāng)前鎖是空閑的
if (c == 0) {
// 通過CAS原子操作方式設(shè)置鎖的狀態(tài),如果為true,表示當(dāng)前線程獲取的鎖抛蚁,
// 為false陈醒,鎖的狀態(tài)被其他線程更改,當(dāng)前線程獲取的鎖失敗
if (compareAndSetState(0, acquires)) {
// 設(shè)置當(dāng)前線程為獨占鎖的線程
setExclusiveOwnerThread(current);
return true;
}
}
// 判斷當(dāng)前線程是不是獨占鎖的線程
else if (current == getExclusiveOwnerThread()) {
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) {
// c表示新的鎖的記錄狀態(tài)
int c = getState() - releases;
// 如果當(dāng)前線程不是獨占鎖的線程瞧甩,就拋出IllegalMonitorStateException異常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
// 標(biāo)志是否可以釋放鎖
boolean free = false;
// 當(dāng)新的鎖的記錄狀態(tài)為0時钉跷,表示可以釋放鎖
if (c == 0) {
free = true;
// 設(shè)置獨占鎖的線程為null
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
protected final boolean isHeldExclusively() {
// 返回當(dāng)前線程是不是獨占鎖的線程
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
final Thread getOwner() {
// 返回獨占鎖的線程
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount() {
// 只有當(dāng)前線程是獨占鎖的線程,才會返回鎖的記錄狀態(tài)state肚逸,否則返回0
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked() {
// 返回鎖是不是被使用狀態(tài)
return getState() != 0;
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
/**
* 非公平鎖
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
// 獲取鎖爷辙,如果沒有獲取到鎖,則當(dāng)前線程要阻塞等待
final void lock() {
// compareAndSetState返回true朦促,表示當(dāng)前線程獲取鎖成功膝晾。
// 因為是非公平鎖,所以不需要判斷AbstractQueuedSynchronizer線程等待隊列是否有值
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
// 調(diào)用acquire方法务冕,獲取鎖
acquire(1);
}
// 嘗試獲取鎖血当,獲取到鎖返回true,沒有獲取到返回false
protected final boolean tryAcquire(int acquires) {
// 調(diào)用父類的nonfairTryAcquire方法
return nonfairTryAcquire(acquires);
}
}
/**
* 公平鎖
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
// 與非公平鎖不同禀忆,因為它要考慮線程等待隊列是否有值
acquire(1);
}
// 嘗試獲取鎖臊旭,與與非公平鎖最大的不同就是調(diào)用hasQueuedPredecessors()方法
// hasQueuedPredecessors方法返回true,表示等待線程隊列中有一個線程在當(dāng)前線程之前箩退,
// 根據(jù)公平鎖的規(guī)則离熏,當(dāng)前線程不能獲取鎖。
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// 獲取鎖的記錄狀態(tài)
int c = getState();
// 如果c==0表示當(dāng)前鎖是空閑的
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 判斷當(dāng)前線程是不是獨占鎖的線程
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
// 更改鎖的記錄狀態(tài)
setState(nextc);
return true;
}
return false;
}
}
// 默認(rèn)創(chuàng)建的是非公平鎖
public ReentrantLock() {
sync = new NonfairSync();
}
// 根據(jù)fair值戴涝,決定創(chuàng)建公平鎖還是非公平鎖
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
// 獲取鎖滋戳,如果獲取不到,就一直等待啥刻。不響應(yīng)中斷請求
public void lock() {
sync.lock();
}
// 獲取鎖奸鸯,如果獲取不到,就一直等待郑什。如果有中斷請求就拋出異常
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
// 嘗試用非公平鎖方式去獲取鎖府喳,立即返回。返回true表示獲取成功蘑拯,返回false表示獲取失敗
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
// 在規(guī)定的unit時間內(nèi)獲取鎖钝满,如果時間到了還沒有獲取到鎖,則返回false申窘,表示獲取失敗
// 如果在線程等待期間有中斷請求就拋出異常
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
// 當(dāng)前線程釋放占用的鎖弯蚜,并喚醒這個鎖上的一個等待線程
public void unlock() {
sync.release(1);
}
// 創(chuàng)建一個Condition對象
public Condition newCondition() {
return sync.newCondition();
}
//
public int getHoldCount() {
return sync.getHoldCount();
}
// 當(dāng)前線程是不是持有鎖的線程
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
// 鎖是否已經(jīng)被持有
public boolean isLocked() {
return sync.isLocked();
}
// 是不是公平鎖
public final boolean isFair() {
return sync instanceof FairSync;
}
// 返回持有鎖的線程,如果null剃法,表示沒有任何線程持有鎖
protected Thread getOwner() {
return sync.getOwner();
}
// 是不是有等待鎖的線程碎捺,即鎖的同步隊列是不是不為空
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
// 等待鎖的線程隊列中有沒有thread線程
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
// 等待鎖線程隊列的長度
public final int getQueueLength() {
return sync.getQueueLength();
}
// 返回等到鎖的線程隊列的集合
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
// condition對象的condition隊列是否有等待線程
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
// condition對象上等待線程的個數(shù)
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
// condition對象上等待線程的集合
protected Collection<Thread> getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}
public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
}