我正在尝试运行以下代码:
在我的构造函数中,我初始化了我的原子布尔值:
Atomic Boolean isChannelActive = new AtomicBoolean(false);
在我的write方法中,我检查这个布尔值并等待:
public ChannelFuture write(ByteBuf msgBuf) {
if (!isChannelActive.get()) {
try {
wait();
} catch (InterruptedException ex) {
logger.Error("Waiting interrupted", ex);
}
}
但问题是这个原子布尔值可以在程序打开时从不同的线程设置:
if (!isChannelActive.get()) {
try{ --- Right on here and program made a context switch at this time.
wait()
所以在这种情况下,我的原子布尔值将为true,我会错过notifyAll()事件,因为上下文切换,它将永远等待。
如何防止此问题?
我知道同步块可能是选项,但我正在为这种情况寻找更优雅的选项。
答案 0 :(得分:2)
如果您正在致电wait()
,那么您已经>> synchronized
阻止 。您的方案是假设的,因为调用wait()
和notifyAll()
的线程必须已获得相同的对象监视器。
因此,在你声称的地方有一个上下文切换是不可能的[1]。在这里使用AtomicBoolean
也没有优势(至少基于你已经展示的内容),一个简单的volatile boolean
也可以正常工作。
[1]并非不可能,您可以编写代码,以便条件检查在同步块之外,但这将故意编写损坏的并发代码。
答案 1 :(得分:2)
您不应混合不同级别的同步机制。
wait/notify
- 这是一个古老的系统,您不再需要使用它。您可以使用wait/notify
或synchronized
来完成Lock
的所有操作。
synchronized
- 这允许您同步代码,以便需要独占访问的部分不会相互干扰。
Lock
s - 有各种不同类型的锁通常可以处理您喜欢的几乎任何访问控制。
Blocking...
- 这是更现代的方法 - 它使用数据结构来确保安全访问,而不是将同步放在代码中。
还有其他一些功能,例如Phaser
和Semaphore
,可用于实现一些更常见的机制。
您尝试同时使用atomics
和wait/notify
。这不会没有困难。
您可能只需要Lock
。
Lock channelActive = new ReentrantLock();
public void test() {
channelActive.lock();
try {
// Do your exclusive stuff here.
} finally {
channelActive.unlock();
}
}