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.