[英]Java concurrency: resettable enabled/disabled wait condition
我想讓一個線程睡眠,直到某個條件關閉。 基本上,我需要三個操作:
enable()
:啟用睡眠模式(如果已啟用則不執行任何操作) disable()
:禁用睡眠模式(如果已禁用則不執行任何操作) await()
:等待睡眠模式被禁用(或者如果睡眠模式已被禁用則立即返回)或者線程被中斷(拋出InterruptedException
) 有了這個,線程A
調用enable()
。 現在,線程B
調用await()
並進入休眠狀態,直到線程A
(或另一個)調用disable()
。 可以重復該循環。
我知道這可以通過wait()
和notify()
輕松完成,但我想知道JDK8是否內置了這樣的功能?
我能找到的最接近的是CountdownLatch(1)
,遺憾的是實現不可重置。
基本上,我只想調用enable()
/ disable()
和await()
,而所有並發概念都在實現中被抽象(盡管await()
應該拋出InterruptedException
,這是不可避免的)。
您也可以使用Semaphor
:
import java.util.concurrent.Semaphore;
public class Switch {
private Semaphore semaphore = new Semaphore(1);
public void enable() {
synchronized(this) {
semaphore.drainPermits(); // 0
semaphore.reducePermits(1); // -1 or 0
}
}
public void disable() {
semaphore.release(2); // 1 or 2
}
public void await() throws InterruptedException {
semaphore.acquire();
semaphore.release();
}
}
Switch
另一種可能實現:
public class Switch {
private final AtomicBoolean state = new AtomicBoolean();
public void enable() {
state.set(true);
}
public void disable() {
if (state.compareAndSet(true, false)) {
synchronized (state) {
state.notifyAll();
}
}
}
public void await() throws InterruptedException {
if (state.get()) {
synchronized (state) {
while (state.get()) {
state.wait();
}
}
}
}
}
你可以使用Condition
:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Switch {
private final Lock lock = new ReentrantLock();
private final Condition on = lock.newCondition();
private final Condition off = lock.newCondition();
private volatile boolean state = true;
public void enable() {
try {
lock.lock();
state = true;
on.signalAll();
} finally {
lock.unlock();
}
}
public void disable() {
try {
lock.lock();
state = false;
off.signalAll();
} finally {
lock.unlock();
}
}
public void await() {
try {
lock.lock();
while(!state) {
try {
off.await();
} catch (InterruptedException e) {
throw new RuntimeException("waiting interrupted.");
}
}
} finally {
lock.unlock();
}
}
}
enable(): enable sleeping mode (do nothing if already enabled)
disable(): disable sleeping mode (do nothing if already disabled)
do nothing if already enabled (disabled)
是一個糟糕的設計,可能會導致細微的錯誤,難以重現和發現。 例如,禁用休眠模式,一個線程調用disable()
,另一個調用enable()
。 根據首先進行的呼叫,模式將永久保持啟用或禁用。 為了使執行更具確定性,必須計算啟用和禁用,並確定(禁用)最終狀態。
相反,你的線程應該交換不相互掩蓋的令牌 。 除了CountdownLatch
(實際上是一個禁止的計數器),JDK還有CyclicBarrier
和Phaser
,它們是可重置的禁止計數器,而Semaphore
是一個權限計數器。
UPDT這個實現可能有用(我沒有測試過):
Phaser p = new Phaser(1);
public void await() {
p.arriveAndAwaitAdvance();
}
public void enable() {
p.register();
}
public void disable() {
p.arriveAndDeregister();
}
對enable()
N次連續調用需要相同數量的disable()
來傳遞等待線程。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.