volatile的理解

只有满足了下面所有的标准后,才能使用volatile变量:

  1. 写入变量时并不依赖变量的当前值;或者能够确保只有单一的线程修改变量的值;
  2. 变量不需要与其他的状态变量共同参与不变约束;
  3. 而且,访问变量时,没有其他的原因需要加锁。

正确使用volatile变量的方式包括:用于确保它们所引用的对象状态的可见性,或者用于标识重要的生命周期时间(比如初始化或者关闭)的发生。

 

---------------------------------分割线-------------------------------------

 

java使用变量时,会先从主内存中将变量读取载入至工作内存,然后处理完以后,再存储写入工作内存。此时当多个内存读取并修改时就会发生并发。

 

而volatile可以确保变量的可见性以及指令有序性。但是volatile不能保证原子性。

 

为什么volatile不能保证原子性?它不是保证了每一时刻每个工作内存的被修饰变量一致吗?

比如 a++;

因为a++的执行等同于a = a + 1;

其中的执行流程分为:

  1. 从主内存读取a至工作内存;
  2. 将a与1相加;
  3. 将相加结果赋给a;
  4. 将a写回主内存。

此时当两个线程均执行至2、3步之间时,因为变量a未产生变化,因此对于各线程来说,a是一致的。此时某个线程执行了第4步,然后另外的线程已经执行完第2步,故这个回写的a值就会覆盖之前的a。

 

被volatile修饰的变量,其read、load、use这三个动作必定按顺序执行且中间不会有其他动作。assign、store、write同上面三个动作。

 

要是还不明白就看

https://blog.csdn.net/sureSand/article/details/82557274

 

 

volatile是如何保证可见性的呢?被volatile修饰的变量发生变化时,会将其他工作内存中的该变量全部无效化,使得其他线程需要重新读取载入变量,故保证了可见性。

 

被volatile修饰的变量V有三个规则,这三个规则要求:

  1. 要求在工作内存中,每次使用V前都必须先从主内存刷新最新的值,用于保证能看见其他线程对变量V所做的修改后的值;
  2. 要求在工作内存中,每次修改V后都必须立刻同步回主内存中,用于保证其他线程可以看到自己对变量V所做的修改;
  3. 这条规则要求volatile修饰的变量不会被指令排序优化,保证代码的执行顺序与程序的顺序相同。

 

其实我一直疑惑的是可见性,普通变量为什么不具备可见性?

https://www.cnblogs.com/tv151579/p/9395452.html

 

       // 线程1

      new Thread(new Runnable() {

            public void run() {

                int i = 0;

                while (Test01.is) {

                    i++;

                    // String a = new String("a");

                }

            }

        }).start();

 

        try {

            TimeUnit.SECONDS.sleep(1);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

 

        // 线程2

        new Thread(new Runnable() {

            public void run() {

                // 设置is为false,使上面的线程结束while循环

                Test01.is = false;

             }

        }).start();

 

这段代码运行时,程序不会立刻停止。因为线程1一直在计算,即CPU一直被占据着,此时CPU不会遵循jvm优化基准。而我们要向CPU遵循jvm优化基准,就要是CPU空闲下来,而此时将操作放在内存分配上时,CPU就会空闲下来,遵循jvm优化基准。

 

因此上面程序只要放开String a = new String(a);就可以结束程序。

 

综合上面的理解,我们应该在什么时候使用volatile?按语义上来说,应该是需要确保可见性和指令不重排时使用。但实际上开发中,CPU一般不会一直占据线程,大部分都会有内存分配等等操作,所以除非是以上这种特殊情况,大部分时候我们使用volatile应该是为了防止指令重排。当我们遇上某些变量的运用绝对不能被重排时,就可以考虑使用volatile,而不是synchronized。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值