聊聊高并发(二十七)解析java.util.concurrent各个组件(九) 理解ReentrantLock可重入锁
這篇講講ReentrantLock可重入鎖,JUC里提供的可重入鎖是基于AQS實現的阻塞式可重入鎖。這篇?聊聊高并發(fā)(十六)實現一個簡單的可重入鎖?模擬了可重入鎖的實現。可重入鎖的特點是:
1. 是互斥鎖,基于AQS的互斥模式實現,也就是說同時只有一個線程進入臨界區(qū),喚醒下一個線程時也只能釋放一個等待線程
2. 可重入,通過設置了一個字段exclusiveOwnerThread來標示當前獲得鎖的線程。獲取鎖操作是,如果當前線程是已經獲得鎖的線程,那么獲取操作成功。把當前狀態(tài)作為獲得鎖次數的計數器,重入一次就加1,釋放一次就減1,直到狀態(tài)為0
3. 1個可重入鎖可以關聯多個Condition條件對象來操作多個條件隊列。Condition接口提供了顯式阻塞/喚醒線程的條件隊列操作。這點比內置鎖和內置條件隊列更具靈活性,1個對象只有1個內置鎖和1個內置條件隊列。看這篇聊聊高并發(fā)(十四)理解Java中的管程,條件隊列,Condition以及實現一個阻塞隊列
?
來看看ReentrantLock的代碼。 它也提供了Sync類來繼承AQS,通過實現tryXXX來擴展功能。
1. nonfairTryAcquire()是非公平的tryAcquire操作,可以無視AQS等待隊列,直接通過判斷狀態(tài)來嘗試獲取鎖,并把當前線程設置為獲取鎖的線程來支持可重入性
2. tryRelease()方法通過修改狀態(tài)來釋放鎖,如果狀態(tài)為0,就把exclusiveOwnerThread設置為空,給之后線程競爭
3. newCondition() 方法每次都創(chuàng)建一個ConditionObject來表示1個條件隊列。在之前講AQS的文章中講了,從條件隊列喚醒后不是立刻獲得鎖,而是從條件隊列進入到了同步隊列,還是得競爭鎖。而隊列鎖的數據結構提供了先來先服務的特性,并且降低了鎖的爭用
?
?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實現。和之前的Semaphore中公平性的含義一樣,非公平性體現在獲取操作時是否等待AQS隊列中的先來的線程,而一旦非公平獲取鎖失敗,那么就進入AQS隊列等待,AQS隊列是FIFO的隊列
1. 可以看到非公平鎖的lock操作,先用最快路徑的方式嘗試了一次獲得鎖,如果獲取失敗,才用acquire操作調用AQS隊列
2. 公平鎖的tryAcquire操作在狀態(tài)為0時要先等待先來的線程都是否后才能獲得鎖,如果有先來的線程,那么就進入AQS隊列。如果當前獲得鎖的線程是自己,就直接獲得鎖,把狀態(tài)加1,體現了可重入
?
?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;
}
}
默認的ReentrantLock使用的是非公平鎖
?
?public ReentrantLock() {
sync = new NonfairSync();
}
ReentrantLock提供了
1. 可中斷和不可中斷的lock操作
2. 提供了tryLock()方式非公平的獲取一次鎖,如果不成功就返回
3. 提供了tryLock(long timeout, TimeUnit unit)的限時鎖
?
?
?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();
??? }
總結
以上是生活随笔為你收集整理的聊聊高并发(二十七)解析java.util.concurrent各个组件(九) 理解ReentrantLock可重入锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 聊聊高并发(二十六)解析java.uti
- 下一篇: 聊聊高并发(二十八)解析java.uti