3

我正在阅读关于“现代 Java 并发”的“JAX London 2011”演示文稿。在持续时间 43:20 - 43:40 之间,一位观众说shutdown下面代码中的变量应该被声明为volatile并且演示者同意它(并说它也被指出过,但他们只是没有得到修改演示文稿)。有问题的代码是:

public abstract class QueueReaderTask implements Runnable {

  private boolean shutdown = false;
  protected BlockingQueue<WorkUnit<String>> lbq;

  public void run() {
    while (!shutdown) {
      try {
        WorkUnit<String> wu = lbq.poll(10, TimeUnit.MILLISECONDS);
        if (wu != null) { doAction(wu.getWork()); }
      } catch (InterruptedException e) {
        shutdown = true;
      }
    }
  }

  public abstract void doAction(String msg);
  public void setQueue(BlockingQueue<WorkUnit<String>> q) { lbq = q; }
}

我的问题:我认为不shutdown应该宣布volatile。我的理由是,shutdown作为 a 的成员Runnable,每个任务/线程都将拥有该变量的不同私有副本。那么,为什么要做呢volatile

但由于这已在 JAX 2011 中讨论过,我假设该听众中有很多专业的 Java 开发人员。我不认为他们所有人都会错过这个!那么,我错过了什么?

PS:-我可以理解,如果变量(可能)由多个线程共享,则应声明该变量volatile,如双重检查锁定模式:

class Foo {
        private volatile Helper helper = null;
        public Helper getHelper() {
            if (helper == null) {
                synchronized(this) {
                    if (helper == null)
                        helper = new Helper();
                }
            }
            return helper;
        }
}
4

1 回答 1

5

每个任务/线程都将具有该变量的不同私有副本。那么,为什么要让它“不稳定”呢?

如果shutdown仅在QueueReaderTask实例内修改布尔值,则您是正确的。在这种情况下shutdown,仅由一个线程修改,不需要volatile.

坦率地说,代码对我来说看起来很奇怪。为什么 catch InterruptedException,设置shutdown布尔值,然后循环并退出。为什么现在只做以下事情?为什么有shutdown国旗?

while (true) {
  try {
    WorkUnit<String> wu = lbq.poll(10, TimeUnit.MILLISECONDS);
    if (wu != null) { doAction(wu.getWork()); }
  } catch (InterruptedException e) {
     Thread.currentThread().interrupt();
     return;
  }
}

也许帖子中删除了额外的代码?如果不是,我想知道这是否是从更大的代码部分复制和粘贴的,在方法调用中shutdown设置为 true 。

PS:-我可以理解,如果变量(可能)由多个线程共享,则应将其声明为“易失性”,如双重检查锁定模式:

正确的。一个典型的模式是shutdown从另一个告诉线程停止处理的线程修改的。在这种情况下,它需要是volatile.

于 2013-03-26T22:36:03.120 回答