[英]Waking up a thread without risking to get blocked
我有一个无限期运行的工作线程,如果无事可做,它将进入睡眠状态一分钟。 有时,另一段代码会产生一些工作,并且想要立即唤醒工作线程。
所以我做了这样的事情(仅用于说明的代码):
class Worker {
public void run() {
while (!shuttingDown()) {
step();
}
}
private synchronized void step() {
if (hasWork()) {
doIt();
} else {
wait(60_000);
}
}
public synchronized wakeMeUpInside() {
notify();
}
}
我不喜欢的只是进入监视器才能唤醒某些东西,这意味着通知线程可能没有充分的理由被延迟。 由于本机同步的选择是有限的,我以为我会切换到Condition
,但是它有完全相同的问题 :
当调用此方法时,实现可能(并且通常确实)要求当前线程持有与此Condition相关联的锁。
这是一个基于信号量的解决方案:
class Worker {
// If 0 there's no work available
private workAvailableSem = new Semaphore(0);
public void run() {
while (!shuttingDown()) {
step();
}
}
private synchronized void step() {
// Try to obtain a permit waiting up to 60 seconds to get one
boolean hasWork = workAvailableSem.tryAquire(1, TimeUnit.MINUTES);
if (hasWork) {
doIt();
}
}
public wakeMeUpInside() {
workAvailableSem.release(1);
}
}
我不确定100%符合您的需求。 注意事项:
wakeMeUpInside
都会添加一个许可。 因此,如果两个线程唤醒了Worker
,它将在没有阻塞的情况下运行doIt
两次。 您可以扩展示例以避免这种情况。 run
方法,该方法将立即将其发送回step
方法,后者将再次等待。 我这样做是因为我假设您有某种原因,即使您没有工作,您也希望每60秒运行一次。 如果不是这种情况,请致电aquire
,您将无限期地等待工作。 根据下面的注释,OP只能运行一次。 在这种情况下,虽然可以调用drainPermits
,但更干净的解决方案是仅使用LockSupport
如下所示:
class Worker {
// We need a reference to the thread to wake it
private Thread workerThread = null;
// Is there work available
AtomicBoolean workAvailable = new AtomicBoolean(false);
public void run() {
workerThread = Thread.currentThread();
while (!shuttingDown()) {
step();
}
}
private synchronized void step() {
// Wait until work is available or 60 seconds have passed
ThreadSupport.parkNanos(TimeUnit.MINUTES.toNanos(1));
if (workAvailable.getAndSet(false)) {
doIt();
}
}
public wakeMeUpInside() {
// NOTE: potential race here depending on desired semantics.
// For example, if doIt() will do all work we don't want to
// set workAvailable to true if the doIt loop is running.
// There are ways to work around this but the desired
// semantics need to be specified.
workAvailable.set(true);
ThreadSupport.unpark(workerThread);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.