保持线程安全,同时防止可能的同步回调死锁
Posted
技术标签:
【中文标题】保持线程安全,同时防止可能的同步回调死锁【英文标题】:Maintain thread safety while preventing deadlock from possibly synchronous callback 【发布时间】:2018-01-05 01:56:01 【问题描述】:我有一个类似下面的 API,其中 Baz
是工作人员实现。
这个Bar
需要是线程安全的,这在与 Baz 的回调交互时会变得很棘手。
需要在回调中引用当前的 baz 实例(可以在工作线程上调用或同步调用)。 cmets 应该显示问题:
final class Bar
final Lock lock = new ReentrantLock();
Baz baz; // Guarded by lock.
void run() // Called by any thread.
lock.lock();
if (baz.isRunning())
lock.unlock();
return;
baz = new Baz();
// If it unlocks here, the next line may execute on the wrong Baz.
// If it doesn't unlock here, there will be a deadlock when done() is called synchronously.
// lock.unlock();
baz.run(new Baz.Callback() // May be called synchronously or by Baz worker thread.
@Override
public void done()
lock.lock();
baz = new Baz();
lock.unlock();
);
有没有一种好方法可以使这项工作正常工作,同时又不会导致死锁?
编辑:更简洁:
final class Foo
final Lock lock = new ReentrantLock();
void run()
lock.lock();
worker.enqueue(new Callback()
@Override void complete()
lock.lock(); // Could cause deadlock.
);
lock.unlock();
【问题讨论】:
【参考方案1】:不确定是否完全得到您想要实现的目标,但也许这就是您想要的?
final class Bar
final Lock lock = new ReentrantLock();
Baz baz = new Baz();
void run()
if (!lock.tryLock())
return;
try
CountdownLatch callbackFlag = new CountdownLatch(1);
baz.run(new Baz.Callback()
@Override
public void done()
callbackFlag.countDown();
);
try
callbackFlag.await(); // better use overloaded method with max timeout waiting. you don't probably want to wait forever
baz = new Baz(); // do you really want to reinit Baz on each execution?
catch (InterruptedException e)
// decide what you want to happen here
finally
lock.unlock();
【讨论】:
不过,baz 分配需要在回调中。 为什么要在回调中引用?我发布的代码确保在回调完成之前 baz 不会重新初始化 无论如何,如果你真的需要,你可以把那行代码移到回调中;无论如何,一切都会好起来的,线程安全也会好的。以上是关于保持线程安全,同时防止可能的同步回调死锁的主要内容,如果未能解决你的问题,请参考以下文章