Java8 ReentrantLock Condition運用
- 在LinkedBlockingQueue中的使用場景
- 1.持有的鎖
- 2.插入元素
- 3.獲取元素
- 4.經驗總結
在LinkedBlockingQueue中的使用場景
下面以LinkedBlockingQueue為例,分析ReentrantLock和Condition的使用,
1.持有的鎖
/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock(); //獲取元素鎖
/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition(); //佇列非空條件
/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock(); //插入元素鎖
/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition(); //佇列未滿條件
2.插入元素
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
if (e == null) throw new NullPointerException(); //若插入空元素,拋出空指標例外
long nanos = unit.toNanos(timeout); //超時時間轉換為時間戳
final int c;
final ReentrantLock putLock = this.putLock; //插入元素鎖
final AtomicInteger count = this.count; //佇列長度
putLock.lockInterruptibly(); //插入元素鎖加鎖
try {
while (count.get() == capacity) { //若佇列已滿,回圈等待
if (nanos <= 0L) //若方法執行超時
return false; //回傳false,插入元素失敗
nanos = notFull.awaitNanos(nanos); //釋放鎖和CPU資源,等待喚醒,若被喚醒,繼續while回圈
}
enqueue(new Node<E>(e)); //若佇列未滿,且未超時,在隊尾插入元素
c = count.getAndIncrement(); //獲取之前的佇列長度,然后將佇列長度+1
if (c + 1 < capacity) //若佇列未滿
notFull.signal(); //喚醒notFull
} finally {
putLock.unlock(); //釋放插入元素鎖
}
if (c == 0) //如果之前的佇列長度為0
signalNotEmpty(); //插入元素后,喚醒notEmpty
return true; //回傳true,插入元素成功
}
3.獲取元素
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
final E x;
final int c;
long nanos = unit.toNanos(timeout); //超時時間轉換為時間戳
final AtomicInteger count = this.count; //佇列長度
final ReentrantLock takeLock = this.takeLock; //獲取元素鎖
takeLock.lockInterruptibly(); //獲取元素鎖加鎖
try {
while (count.get() == 0) { //若佇列為空,回圈等待
if (nanos <= 0L) //若方法執行超時
return null; //回傳null,獲取元素失敗
nanos = notEmpty.awaitNanos(nanos); //釋放鎖和CPU資源,等待喚醒,若被喚醒,繼續while回圈
}
x = dequeue(); //若佇列非空,且未超時,獲取佇列首元素并從佇列洗掉
c = count.getAndDecrement(); //獲取之前的佇列長度,然后將佇列長度-1
if (c > 1) //若佇列非空
notEmpty.signal(); //喚醒notEmpty
} finally {
takeLock.unlock(); //釋放獲取元素鎖
}
if (c == capacity) //如果之前的佇列是滿的
signalNotFull(); //獲取元素后,喚醒notFull
return x; //回傳獲取的元素
}
4.經驗總結
1. Condition:固定模式,配合while回圈使用,1.等待資源滿足條件退出回圈;2.超時退出,
2. LinkedBlockingQueue的實作使用了takeLock、putLock,防止死回圈,代碼中避免同時獲取兩把鎖,例如上面插入元素,釋放putLock 鎖之后再執行signalNotEmpty,獲取takeLock鎖,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/242339.html
標籤:其他
下一篇:單例模式
