volatile理解

多线程程序常考虑三种性质:原子性、可见性、有序性。定义如下:

 1. 原子性:
       一个或多个操作的执行,只有两种情况:(1)全部执行并且执行过程中不会被打断;(2)不执行
 2. 可见性:
        当多个线程访问同一个共享变量时,一个线程修改了变量的值,其他线程能够立即看到被修改的新值。 例如:
             //线程1执行的代码  
                int i = 0;  
                i = 10;  
             //线程2执行的代码  
                j = i;

        当线程1执行完i=10时,其过程是:将i的初始值读入高速缓存中,然后讲高速缓存中 i 的值改为10,再将i的新值刷入内存中;

        若没有可见性,则i的新值未刷入主存时,线程2执行,此时线程2读取内存中的 i 的值为0。(线程1修改了 i 值,线程2没有立即看到)

 3. 有序性:

        程序执行的顺序按照代码中的先后顺序执行。

        为了提高程序效率,编译器会对代码进行优化,将没有依赖关系的指令执行先后顺序进行重排,使指令执行顺序与代码先后顺序不同,但保 证最终的结果一致。虽然指令重排对单线程没有影响,但会影响多线程并发执行的正确性。

在JAVA中实现三种性质的方式:

   原子性是通过同步(Synchronized或Lock锁机制)来实现;

       可见性是通过volatile来实现(保证变量修改后立即写入内存);

       有序性是通过同步或volatile来实现。

volatile的特性与作用:

 1. volatile修饰变量后的特性:

          (1)保证了多个线程对变量操作的可见性,即:一个线程修改了变量值,其他线程立即可见。(保证变量安全,不保证线程安全)

          (2)禁止进行指令重排。(防止编译器自动优化,对代码顺序的指令重新排序)    

 2. volatile保证变量可见性:

          (1)使用volatile修饰的变量,在一个线程中被修改后会强制立即写入内存(不经过线程工作内存,即线程中的寄存器或堆栈空间);

          (2)使用volatile修饰的变量,当有线程修改其值后,其他线程的工作内存中该值无效;

          (3)使用volatile修饰的变量,所有线程必须从内存读取变量值(不经过线程工作内存,即该线程的寄存器或堆栈空间)。  

 3. volatile不保证变量原子性:

           某些情况下,volatile可以实现变量原子性,如:long和double都是64位宽,32位操作系统对这种类型变量的读取分两部分,第一次读取32位,第二次读取剩下的32位。读取操作不是原子性的,当用volatile修饰(volatile long)时,可以将操作变为原子性操作。

 4. volatile保证变量有序性:

           使用volatile修饰的变量,编译器不能对该变量所在指令重排(例如:该指令之前的指令集合相互可以重排,但不能重排到该指令后面)

原文地址:https://www.cnblogs.com/ladawn/p/8253531.html