我正在参加“JAX London 2011” presentation on "Modern Java Concurrency" 。在 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
我的推理是 shutdownRunnable 的成员,每个任务/线程都将具有该变量的不同私有(private)副本。那么,为什么要做 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;
        }
}

最佳答案



如果 shutdown boolean 值仅从 QueueReaderTask 实例中修改,则您是正确的。在这种情况下, shutdown 只会被一个线程修改,不需要是 volatile

坦率地说,代码对我来说看起来很奇怪。为什么要捕获 InterruptedException ,设置 shutdown boolean 值,然后循环并退出。为什么现在只需执行以下操作?为什么有 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。



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

关于java - 是否有必要使这个变量变得易变?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15648683/

10-11 03:45