volatile作用

1.保证可见性

2.禁止指令重排序

重排序

int mod = 0;
int a = 1;
public void chmod(){
    a = 2;
    mod = 1
}
public void test(){
    if(mod == 1){
        System.out.println(a);
    }
}

由于指令重排序会导致一些前后没有直接联系的代码顺序问题,如chmod中a和mod不直接联系,可能出现mod先为1的情况,此时如果有另一线程执行test就会出问题。

故而使用volatile通过加内存屏障,可以使修饰的变量被执行时,保证之前的命令执行完毕。

单例模式双检锁为什么要volatile

public class Single{
    private volatile static MyService service;
    private Single(){
        // 私有化构造函数
    }
    public static MyService get(){
        if(service == null){
            synchronized(Single.class){
                if(service == null){
                    service = new Single();
                }
            }
        }
        return service;
    }
}

如上代码,如果没有volatile,线程a执行service = new Single()时,可能导致原本的分配内存、初始化对象、分配地址改变顺序,比方说变成分配内存、分配地址、初始化对象。

这样当分配好地址后,还没初始化对象,正好b线程也进来,判断service非null,直接返回了一个未初始化的service,因此需要volatile。