聊聊高并发(二十七)解析java.util.concurrent各个组件(九) 理解ReentrantLock可重入锁
這篇講講ReentrantLock可重入鎖,JUC里提供的可重入鎖是基于AQS實(shí)現(xiàn)的阻塞式可重入鎖。這篇?聊聊高并發(fā)(十六)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的可重入鎖?模擬了可重入鎖的實(shí)現(xiàn)。可重入鎖的特點(diǎn)是:
1. 是互斥鎖,基于AQS的互斥模式實(shí)現(xiàn),也就是說(shuō)同時(shí)只有一個(gè)線程進(jìn)入臨界區(qū),喚醒下一個(gè)線程時(shí)也只能釋放一個(gè)等待線程
2. 可重入,通過(guò)設(shè)置了一個(gè)字段exclusiveOwnerThread來(lái)標(biāo)示當(dāng)前獲得鎖的線程。獲取鎖操作是,如果當(dāng)前線程是已經(jīng)獲得鎖的線程,那么獲取操作成功。把當(dāng)前狀態(tài)作為獲得鎖次數(shù)的計(jì)數(shù)器,重入一次就加1,釋放一次就減1,直到狀態(tài)為0
3. 1個(gè)可重入鎖可以關(guān)聯(lián)多個(gè)Condition條件對(duì)象來(lái)操作多個(gè)條件隊(duì)列。Condition接口提供了顯式阻塞/喚醒線程的條件隊(duì)列操作。這點(diǎn)比內(nèi)置鎖和內(nèi)置條件隊(duì)列更具靈活性,1個(gè)對(duì)象只有1個(gè)內(nèi)置鎖和1個(gè)內(nèi)置條件隊(duì)列。看這篇聊聊高并發(fā)(十四)理解Java中的管程,條件隊(duì)列,Condition以及實(shí)現(xiàn)一個(gè)阻塞隊(duì)列
?
來(lái)看看ReentrantLock的代碼。 它也提供了Sync類來(lái)繼承AQS,通過(guò)實(shí)現(xiàn)tryXXX來(lái)擴(kuò)展功能。
1. nonfairTryAcquire()是非公平的tryAcquire操作,可以無(wú)視AQS等待隊(duì)列,直接通過(guò)判斷狀態(tài)來(lái)嘗試獲取鎖,并把當(dāng)前線程設(shè)置為獲取鎖的線程來(lái)支持可重入性
2. tryRelease()方法通過(guò)修改狀態(tài)來(lái)釋放鎖,如果狀態(tài)為0,就把exclusiveOwnerThread設(shè)置為空,給之后線程競(jìng)爭(zhēng)
3. newCondition() 方法每次都創(chuàng)建一個(gè)ConditionObject來(lái)表示1個(gè)條件隊(duì)列。在之前講AQS的文章中講了,從條件隊(duì)列喚醒后不是立刻獲得鎖,而是從條件隊(duì)列進(jìn)入到了同步隊(duì)列,還是得競(jìng)爭(zhēng)鎖。而隊(duì)列鎖的數(shù)據(jù)結(jié)構(gòu)提供了先來(lái)先服務(wù)的特性,并且降低了鎖的爭(zhēng)用
?
?abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* Performs {@link Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
abstract void lock();
/**
* Performs non-fair tryLock. tryAcquire is
* implemented in subclasses, but both need nonfair
* try for trylock method.
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
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;
}
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
// Methods relayed from outer class
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked() {
return getState() != 0;
}
/**
* Reconstitutes this lock instance from a stream.
* @param s the stream
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
?
同樣提供了公平鎖和非公平鎖的FairSync和NonfairSync實(shí)現(xiàn)。和之前的Semaphore中公平性的含義一樣,非公平性體現(xiàn)在獲取操作時(shí)是否等待AQS隊(duì)列中的先來(lái)的線程,而一旦非公平獲取鎖失敗,那么就進(jìn)入AQS隊(duì)列等待,AQS隊(duì)列是FIFO的隊(duì)列
1. 可以看到非公平鎖的lock操作,先用最快路徑的方式嘗試了一次獲得鎖,如果獲取失敗,才用acquire操作調(diào)用AQS隊(duì)列
2. 公平鎖的tryAcquire操作在狀態(tài)為0時(shí)要先等待先來(lái)的線程都是否后才能獲得鎖,如果有先來(lái)的線程,那么就進(jìn)入AQS隊(duì)列。如果當(dāng)前獲得鎖的線程是自己,就直接獲得鎖,把狀態(tài)加1,體現(xiàn)了可重入
?
?static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
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;
}
}
默認(rèn)的ReentrantLock使用的是非公平鎖
?
?public ReentrantLock() {
sync = new NonfairSync();
}
ReentrantLock提供了
1. 可中斷和不可中斷的lock操作
2. 提供了tryLock()方式非公平的獲取一次鎖,如果不成功就返回
3. 提供了tryLock(long timeout, TimeUnit unit)的限時(shí)鎖
?
?
?public void lock() {
sync.lock();
}
?public void lockInterruptibly() throws InterruptedException {
??????? sync.acquireInterruptibly(1);
??? }
public boolean tryLock() {
??????? return sync.nonfairTryAcquire(1);
??? }
public boolean tryLock(long timeout, TimeUnit unit)
??????????? throws InterruptedException {
??????? return sync.tryAcquireNanos(1, unit.toNanos(timeout));
??? }
public Condition newCondition() {
??????? return sync.newCondition();
??? }
總結(jié)
以上是生活随笔為你收集整理的聊聊高并发(二十七)解析java.util.concurrent各个组件(九) 理解ReentrantLock可重入锁的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 聊聊高并发(二十六)解析java.uti
- 下一篇: 聊聊高并发(二十八)解析java.uti