volatile是否只适用于primitve type? 也就是说,java对象是否也存在 主内存+工作内存副本这样的机制?
结论是:volatile对object reference也适用。
具体来说,
如果一个变量原来是指向对象A的,一个线程把它指向对象B后,另一个线程并不能感知这种变化。
例如,
package player.kent.chen.learn.hivolatile;
/**
* 循环直到有人喊停
*/
public class LoopUntilCommandForString {
private static final String YES = "yes";
private static final String NO = "no";
private String stop = NO;
/**
* 循环直到有人喊停
*/
public void loop() {
System.out.println("Loop started");
while (stop == NO) {
;
}
System.out.println("Stopped because somebody said so");
}
/**
* 喊停
*/
public void sayStop() {
stop = YES;
System.out.println("Stop said");
}
public static void main(String[] args) throws InterruptedException {
final LoopUntilCommandForString luc = new LoopUntilCommandForString();
Thread t = new Thread(new Runnable() {
public void run() {
luc.loop();
}
});
t.start(); //启动循环线程
Thread.sleep(1000);
luc.sayStop(); //喊停
}
}
执行结果是:死循环。 如果在 "private String stop = NO;" 中间插入一个volatile关键字再执行上面的程序,就不会死循环了。
下面说另一个问题:
对于non-volatile object variable,如果我们改变的不是变量的reference, 而是变量对象内部的值,会不会有可见性问题?
package player.kent.chen.learn.hivolatile;
/**
* 循环直到有人喊停
*/
public class LoopUntilCommandForBoolBean {
private BoolBean bean = new BoolBean(false);
/**
* 循环直到有人喊停
*/
public void loop() {
System.out.println("loop starts");
while (!bean.isStop()) {
;
}
System.out.println("Stopped because somebody said so");
}
/**
* 喊停
*/
public void sayStop() {
bean.setStop(true);
System.out.println("Stop said");
}
public static void main(String[] args) throws InterruptedException {
final LoopUntilCommandForBoolBean luc = new LoopUntilCommandForBoolBean();
Thread t = new Thread(new Runnable() {
public void run() {
luc.loop();
}
});
t.start(); //启动循环线程
Thread.sleep(1000);
luc.sayStop(); //喊停
}
private static final class BoolBean {
private boolean stop;
/**
* @param stop
*/
public BoolBean(boolean stop) {
super();
this.stop = stop;
}
public boolean isStop() {
return stop;
}
public void setStop(boolean stop) {
this.stop = stop;
}
}
}
执行结果如你所料,是死循环。
如果把BoolBean.stop声明为volatile,执行结果也如你所料:不会死循环。
但如果BoolBean.stop不声明为volatile,而在"private BoolBean bean = new BoolBean(false);" 中间插入一个volatile关键字,会怎么样呢? 在我的HotSpot 1.6 JDK上的实验结果是:不会死循环。
这是不是意味着:object前加个volatile可以使这个object里面的属性自动变成volatile? 我找了一些资料,没找到任何证据支持这种说法;为了保险起见,建议还是把BoolBean.stop,即object里面的属性, 也声明为volatile.