我正在参加“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
。我的推理是
shutdown
是 Runnable
的成员,每个任务/线程都将具有该变量的不同私有(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/