我正在经历一场“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
的成员,每个任务/线程将拥有该变量的不同私有副本。那么,为什么要成为volatile
?
但是自从JAX 2011中讨论过这个问题以来,我假设在这些受众中有很多专业的Java开发人员。我不认为所有人都会错过这个! 那么,我错过了什么?
P.S: -
我可以理解,如果变量(可能)被多个线程共享,则应该声明变量volatile
,如Double-Checked-Locking模式:
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}
答案 0 :(得分:5)
每个任务/线程都将拥有该变量的不同私有副本。那么,为什么要让它“不稳定”?
你是正确的如果只在shutdown
实例中修改了QueueReaderTask
布尔值。在这种情况下,shutdown
仅由一个线程修改,不需要volatile
。
坦率地说,代码看起来很奇怪。为什么要捕获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 。
P.S: - 我可以理解,如果变量(可能)由多个线程共享,则应该声明变量'volatile',如Double-Checked-Locking模式:
右。典型的模式是从另一个线程修改shutdown
,该线程告诉线程停止处理。在这种情况下,它必须是volatile
。