JMM: 断点调试可能使不可见的变量变成可见

如果一个变量没有使用volatile标识,则可能存在跨线程可见性问题; 但经验发现,断点调试时,这个可见性问题可能会消失。

比如,

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;
        }
    }
}

直接运行时,这个程序会陷入死循环; 但你如果在isStop()处设个断点,以debug的方式来运行程序,很有可能会使stop变量变得可见。

具体为什么会这样,我找了很久没找到答案; 但这个现象可以提醒我们:
对于牵涉到JMM的问题,用debug方式运行得没问题,不代表直接运行也没问题

Leave a Comment

Your email address will not be published.

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