栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

volatile关键字作用及Dome

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

volatile关键字作用及Dome

        关于volatile关键字的作用,网上有很多解释和dome,但是有一些Dome是运行后达不到效果的。我亲试并整理了下面两个Dome留做笔记。

本文连接:volatile关键字作用及Dome_张三的博客-CSDN博客

volatile的作用1.保证数据的可见性。2防止指命重排序。备注:不能保证原子性

1.保证数据保见性

1.1为什么会有可见性的问题?因为共享对象是共享内存中(这里理解的是放到方法区或堆),每个线程使用的时候会将对象拿到线程内存中(线程栈)。加入volatile关键字后,线程会每次使用前去共享内存中拿,做完写操作也会及时的写入,从而保证数据的可见性。附带一个Dome。

图来自百度百科

1.2Dome解释:

不加volatile时,子线程修改了flag的状态后,主线程取不到最新变量,会一直什么都不打印
加volatile时,子线程修改了flag的状态后,主线程取得到最新变量,会一直打印flag is true

Dome可以去掉volatile关键字来试一下结果。

package com.example.demo.jvm;


public class VolatileVisible {
    
    private static  boolean flag = false;

    
        public static void main(String[] args) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                    }
                    flag = true;
                    System.out.println("flag=" + flag);
                }
            }).start();
            while (true) {
                if (flag) {
                    System.out.println("flag is true");
                }
            }
        }
}


2防止内存的重排序 

2.1什么是重排序:CPU为了提升性能,有时候会对我们的指命进行重排序,当时是指的未相互引用同样数据的指令,否则就结果问题。比如我们执行一个 User user = new User();User构造方法有一句打印语句。这时候我们的指令会被拆分成1.new 内存空间,2执行构造方法中的打印语句,3赋值给user对象。这时候CPU为了性能可能执行的是1,3,2这样的语句。如果是单线程那这样问题不大,但是在多线程共享的对象的话则会产生问题,因为其它线程会认为user被赋值的时候构造函数已经执行完了。这时就发生了指命的重排序,这时候我们就需要加入volatile。

2.2Dome解释 

* 两个线程,每个线程操作两个变量。t11代表线程1的第一个变量,以此类推。
* 如果出现t12和t22同时为零则说明cpu没有按编写顺序去执行,即cpu发生了重排序。
* 代码逻辑解释:
* 先以cpu不会乱序来看,
* t12为0时,说明线程1执行完第二句话时,线程2还没有执行,这时线程2的代码去执行.
* 以这种顺序来看,t22必然不能为0。如果为0则说明cpu没有按我们预想的顺序去执行,即发生了重排序。

我们不带voliatile时,执行一段时间会出现重排序,加入voliatile后不会出现。可以用代码中的注释调试一下。

package com.example.demo.jvm;

public class VolatileReOrder {
    
    private static  int t11 = 0,t12 = 0, t21 = 0,t22 = 0;

    public static void main(String[] args) throws InterruptedException {
        cpuReOrder();
    }

    
    private static void cpuReOrder() throws InterruptedException {
        int i = 0;
        for(;;){
            i++;
            t12=0;t11=0;t21=0;t22=0;//恢复变量
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    t11 = 1;
                    t12 = t21;
                }
            });
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    t21 = 1;
                    t22 = t11;
                }
            });
            t1.start();t2.start();
            t1.join();t2.join();//等待执行完毕
            if(t12 == 0 && t22 == 0){
                System.out.println("出现重排序i="+i);
                break;
            }
        }
    }
}

重排序比较难复现,去掉voliatile关键字执行很长时间才行。截图:

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/658136.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号