• volatile关键字的可见性_java培训


    volatile关键字的可见性

    volatile 修饰的成员变量在每次被线程访问时,都强迫从主存(共享内存)中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到主存(共享内存)。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值,这样也就保证了同步数据的可见性。

    TestVolatile.java

    public class TestVolatile extends Thread {
        private boolean isRunning = true;
        int m;

        public boolean isRunning() {
            return isRunning;
        }

        public void setRunning(boolean isRunning) {
            this.isRunning = isRunning;
        }

        @Override
        public void run() {
            System.out.println(“进入run”);
            while (isRunning == true) {
                int a = 2;
                int b = 3;
                int c = a + b;
                m = c;
            }
            System.out.println(m);
            System.out.println(“停止!”);
        }

        public static void main(String[] args) throws InterruptedException {
            TestVolatile testVolatile = new TestVolatile();
            testVolatile.start();
            Thread.sleep(1000);
            testVolatile.setRunning(false);
            System.out.println(“赋值:false”);
        }
    }

    运行结果:

    进入run
    赋值:false

    TestVolatile类中的isRunning变量没有加上volatile关键字时,运行以上代码会出现死循环,这是因为isRunning变量虽然被修改但是没有被写到主存中,这也就导致该线程在本地内存中的值一直为true,这样就导致了死循环的产生。 解决办法也很简单:isRunning变量前加上volatile关键字即可。这样运行就不会出现死循环了。

    加上volatile关键字后的运行结果:

    进入run
    赋值:false
    5
    停止!

    假如你把while循环代码里加上任意一个输出语句

        @Override
        public void run() {
            System.out.println(“进入run”);
            while (isRunning == true) {
                int a = 2;
                int b = 3;
                int c = a + b;
                m = c;
                System.out.println(“while内”+m);;//输出语句
            }
            System.out.println(m);
            System.out.println(“停止!”);
        }

    结果如下:

    5
    5
    5
    5
    5
    5
    5
    5
    停止!
    赋值:false

    或者加上sleep方法

        @Override
        public void run() {
            System.out.println(“进入run”);
            while (isRunning == true) {
                int a = 2;
                int b = 3;
                int c = a + b;
                m = c;
                try {
                    Thread.sleep(1000);//sleep方法
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(m);
            System.out.println(“停止!”);
        }

    结果如下:

    进入run
    赋值:false
    5
    停止!

    你会发现死循环也会停止,不管isRunning变量是否被加上了上volatile关键字。

    因为:JVM会尽力保证内存的可见性,即便这个变量没有加同步关键字。换句话说,只要CPU有时间,JVM会尽力去保证变量值的更新。这种与volatile关键字的不同在于,volatile关键字会强制的保证线程的可见性。而不加这个关键字,JVM也会尽力去保证可见性,但是如果CPU一直有其他的事情在处理,它也没办法。最开始的代码,一直处于死循环中,CPU处于一直占用的状态,这个时候CPU没有时间,JVM也不能强制要求CPU分点时间去取最新的变量值。而加了输出或者sleep语句之后,CPU就有可能有时间去保证内存的可见性,于是while循环可以被终止。

     

  • 相关阅读:
    和为s的两个数字——每日两题
    MySQL下载安装配置方法
    什么是专线网络?互联网专线为什么贵
    责任链模式应用案例
    JavaScript-es6-新版语法-export-import
    KingbaseES V8 GIS数据迁移方案(2. Kingbase GIS能力介绍)
    【C++ 算法进阶】算法提升七
    清晰梳理最全日志框架关系与日志配置-SpringBoot 2.7.2 实战基础
    在用户同意隐私政策前,您的应用获取了用户的ANDROID ID,不符合华为应用市场审核标准。
    数据治理资料整理合集
  • 原文地址:https://blog.csdn.net/zjjcchina/article/details/127547349