Volatile关键字的基本作用和原理

1.对于volatile关键字,首先是保持内存的可见性

    1.1 内存可见性(Memory Visibility):所有的线程都能看到共享内存的最新状态。

    1.2 Java中对于变量的读写是通过下列原子操作完成工作内存与主内存的数据交互:

           1.lock:作用于主内存,把变量标识为线程独占状态。

           2.unlock:作用于主内存,解除线程对变量的独占状态。

           3.read:作用于主内存,把一个变量的值从主内存中传递至工作内存中。

           4.load:作用于工作内存,把read操作传递过来的变量值放入工作内存的变量副本中。

           5.use:作用于工作内存,把工作内存当中的某个变量的值传递给执行引擎。

           6.assign:作用于工作内存,把一个从执行引擎接收到的值赋值给工作内存中的变量。

           7.store:作用于工作内存的变量,把工作内存中的变量的值传递到主内存中。

           8.write:作用于主内存中的变量,把store操作传递过来的变量的值放入主内存的变量中。

    1.3 Volatile关键字如何保持内存可见性,volatile关键字的特殊规则:

           1.read,load,use是一个连续的操作过程。

           2.assign,store,write同样是一个连续的操作过程。

           根据上述规则,使用volatile关键字能够以下结果:

           1.每次读取前必须从主内存中刷线最新的值。

           2.每次写入后必须将最新的值同步到内存中。

      也就是说,volatile关键字修饰的变量看到的永远是自己的最新值。同时,线程A中对变量的最新修改,对于线程B是可见的。即Volatile修饰的成员变量在每次被线程访问时,都被迫从主内存中重读该成员变量。而且,当成员变量发生变化时,强迫线程将变化值写回到主内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

2.解决数据失效问题

     2.1 如下代码展示数据失效:

      public class data {
          private int threadUnSafedValue;
          public int get(){
               return threadUnSafedValue;
            }
          public void set(int threadUnSafedValue){
               this.threadUnSafedValue = threadUnSafedValue;
            }
       }

threadUnSafedValue是非线程安全的,由于getter和setter方法都没有在同步的情况下进行。即当线程A调用getter方法的同时线程B可能回看到更新后的threadUnSafedValue值,当然,也有可能看不到。

为了让线程A在调用getter方法的时候,线程B一定能看到更新后的threadUnSafedValue值,我们需要将threadUnSafedValue声明为volatile变量。

public volatile int threadUnSafedValue;

3.注意点

     根据上述内容,初步了解了volatile关键字的作用和原理,但是很容易出现错把volatile变量当作原子变量。因为volatile关键字在使用变量的读,写时具有了"原子性",但是该"原子性"仅仅局限于变量(包括引用)的读写,却无法涵盖变量上的其他任何操作如:

     1.基本类型的自增,即threadUnSafedValue++操作不是原子性的。

     2.对象的任何非原子成员(包括成员变量和成员方法)的调用不是原子的。

至此,如果我们希望上述操作拥有原子性,我们可以采用锁,原子变量等。

4.Volatile关键字的使用建议

     1.在两个或者更多线程访问的成员变量时使用Volatile关键字。

     2.当要访问的变量已在synchronized代码块中,或者为常量时,不必使用Volatile关键字。

     3.由于使用volatile关键字会屏蔽掉JVM中一些代码优化,导致代码效率较低,因此在必要的时候才使用Volatile关键字。

     

发布了22 篇原创文章 · 获赞 5 · 访问量 2196

猜你喜欢

转载自blog.csdn.net/calm_encode/article/details/103875555