java:具有 getter 和 setter 的“易失性”私有字段
我们是否应该声明私有字段,就好像实例化在多个线程中使用一样?volatile
在 Effective Java 中,有一个示例,其中代码在没有易失性的情况下无法正常工作:
import java.util.concurrent.TimeUnit;
// Broken! - How long would you expect this program to run?
public class StopThread {
private static boolean stopRequested; // works, if volatile is here
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested)
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
解释说
while(!stopRequested)
i++;
被优化为如下:
if(!stopRequested)
while(true)
i++;
因此,后台线程看不到 的进一步修改,因此它将永远循环。(顺便说一句,该代码在没有JRE7的情况下终止。stopRequested
volatile
现在考虑以下类:
public class Bean {
private boolean field = true;
public boolean getField() {
return field;
}
public void setField(boolean value) {
field = value;
}
}
和一个线程,如下所示:
public class Worker implements Runnable {
private Bean b;
public Worker(Bean b) {
this.b = b;
}
@Override
public void run() {
while(b.getField()) {
System.err.println("Waiting...");
try { Thread.sleep(1000); }
catch(InterruptedException ie) { return; }
}
}
}
上面的代码在不使用易失性的情况下按预期工作:
public class VolatileTest {
public static void main(String [] args) throws Exception {
Bean b = new Bean();
Thread t = new Thread(new Worker(b));
t.start();
Thread.sleep(3000);
b.setField(false); // stops the child thread
System.err.println("Waiting the child thread to quit");
t.join();
// if the code gets, here the child thread is stopped
// and it really gets, with JRE7, 6 with -server, -client
}
}
我认为由于公共 setter,编译器/JVM 永远不应该优化调用 的代码,但本文说有一些“Volatile Bean”模式(模式 #4),应该应用它来创建可变的线程安全类。更新:也许那篇文章仅适用于 IBM JVM?getField()
问题是:JLS的哪一部分显式或隐式地表示具有公共getter/setter的私有基元字段必须声明为(或者它们不必)?volatile
很抱歉有一个很长的问题,我试图详细解释这个问题。如果有什么不清楚的地方,请告诉我。谢谢。