深入理解java虚拟机第五部分高效并发

volatile是java虚拟机提供最轻量级的同步机制。

volatile两个特性:1,保证同步的变量对所有线程是可见的。虽然对所有线程是即时可见的,但是却不保证原子性,也就是不保证线程安全,比如对于创建20个线程,每个线程都执行i++操作,执行100次,但是i输出的结果小于2000。因为一条i++用javap反编译是由4条指令来执行的。所以我们通过synchronized来保证原子性。 下面给出一个volatile适用的场景: 当shutdown()方法被执行时,保证所有线程中执行dowork()方法都立即停下来。

1 volatile boolean    shutdownRequested;
2 public void shutdown(){
3     shutdownRequested = true;
4 }
5 public void dowork(){
6     while(!shutdownRequested){
7     ``````````
8     }
9 }

2,禁止指令重排序优化。

先给出一个简单的例子

 1public class Singleton{
 2   private volatile static Singleton instance;
 3   public static Singleton getInstance(){
 4       if(instance == null){
 5          synchronized(Singleton.class){
 6            if(instance==null){
 7                instance = new Singleton();
 8            }
 9          }    
10       }  
11       return instance;
12   }        
13 }
14 public static void main(String[] args){
15         Singleton.getInstance();
16 }

其中instance变量被赋值的部分执行了“lock addl $0x0,(%esp)”操作,这个操作相当于一个内存屏障(memory Barrier),重排序后的指令不能放到内存屏障之前的位置。

对原子性,可见性与有序性理解:

java内存模型是围绕着在并发过程中如何处理原子性、可见性与有序性这三个特性来建立的。

原子性:原子性操作包括,read、load、assign、use、store、和write。lock和unlock、synchronized块之间的操作也是原子性。

可见性:volatile,当一个线程修改了共享变量的值,其他线程能够立即得到这个修改的值。synchronized在变量执行unlock操作之前,必须先把此变量同步回主内存中和finally被finally修饰的字段在构造器中一旦初始化完成,并且构造器没有把this的引用传递出去,那在其他线程中都能看到finally字段。

有序性:volatile本身就有禁止指令重排序的语义,而synchronized则是由“一个变量在同一时刻只允许一个线程对其执行unlock操作”。

我们衡量并发线程安全的时候不要受到时间顺序的干扰,一切必须以,先行发生原则为准。

原文地址:https://www.cnblogs.com/ScarecrowAnBird/p/6971301.html