【问题标题】:Atomic Boolean usage in multithreaded application多线程应用程序中的原子布尔使用
【发布时间】:2017-02-10 08:42:38
【问题描述】:

我正在尝试运行以下代码:

在我的构造函数中,我初始化了我的原子布尔值:

Atomic Boolean isChannelActive = new AtomicBoolean(false);

在我的写方法中,我检查这个布尔值并等待:

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()

所以在这种情况下,我的原子布尔值将为真,我错过了 notifyAll() 事件,并且由于上下文切换将永远等待。

我怎样才能防止这个问题?

我知道同步块可能是一种选择,但我正在为这种情况寻找更优雅的选择。

【问题讨论】:

  • 如果您正在调用wait(),您已经 synchronized 块中。
  • Conditions 可以替代吗?
  • 我还看了一下 CountdownLatch 机制,并且工作正常。 CountdownLatches 可以解决同样的问题

标签: java multithreading synchronization atomic context-switch


【解决方案1】:

您不应该混合不同级别的同步机制。

  1. wait/notify - 这是一个您不再需要使用的古老系统。您可以通过wait/notify 完成的所有操作都可以通过synchronizedLocks 完成。

  2. synchronized - 这允许您同步代码,以便需要独占访问的部分不会相互干扰。

  3. Locks - 有多种不同类型的锁通常可以处理您喜欢的几乎任何访问控制。

  4. Blocking... - 这是更现代的方法 - 它使用数据结构来确保安全访问,而不是将同步放在代码中。

  5. 还有更多功能集,例如 PhaserSemaphore,可用于实现一些更常见的机制。

您正在尝试同时使用atomicswait/notify。这不会没有困难。

您可能只需要一个Lock

Lock channelActive = new ReentrantLock();

public void test() {
    channelActive.lock();
    try {
        // Do your exclusive stuff here.
    } finally {
        channelActive.unlock();
    }

}

【讨论】:

    【解决方案2】:

    如果您调用 wait(),您已经 synchronized 块。您的场景是一种假设,因为调用 wait()notifyAll() 的两个线程必须获得相同的对象监视器。

    因此,在您声称的地方不可能有上下文切换[1]。在这里使用AtomicBoolean 也没有任何优势(至少基于您所展示的内容),一个简单的volatile boolean 也可以正常工作。

    [1] 并非不可能,您可以编写代码,使条件检查位于同步块之外,但这会故意编写损坏的并发代码。

    【讨论】:

      猜你喜欢
      • 2021-11-17
      • 2011-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-07
      • 1970-01-01
      • 2013-12-25
      • 2021-11-12
      相关资源
      最近更新 更多