例示:volatile是否只适用于primitve type ?

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.

Leave a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.