66、synchronized和volitail的区别

解决并发共享变量问题需要解决三个问题:原子性、可见性、有序性

synchronize:保证原子性、可见性、有序性(多线程顺序执行)

volatile:保证可见性、有序性(禁止指令重排序)

public class Singleton {
    private static volatile Singleton s;//1,volatile修饰的必要性
    private Singleton(){};//必须是private
    public static Singleton getInstance() {
        if(s == null) {//2
            synchronized (Singleton.class) {//3
                if(s == null) {//4
                    s = new Singleton();//问题关键:步骤5分为三步,存在指令重排可能性
                }
            }
        }
        return s;//6
    }
}

位置5可分为三个步骤:

1、memory=allocate();// 分配内存 相当于c的malloc
2、ctorInstanc(memory) //初始化对象
3、s=memory //设置s指向刚分配的地址

由于synchronize不保证单个线程内部指令的顺序,比如线程A在位置5的执行顺序有可能是1-2-3,也有可能是1-3-2,如果是1-3-2的情况,线程A执行完步骤3给s对象分配了地址;此时来个线程B,那么在位置2判断s就不为null,但是此时线程A还没有初始化对象,就会导致线程B拿到的s出错,线程A不会出错。

所以位置3加锁后,只能保证多线程串行执行加锁部分的代码块,不能保证位置5里面的指令执行顺序,所以对象s用volatile修饰 ,禁止指令重排序,从而保证了代码执行的正确性。

总结:步骤1用volatile修饰对象,就是为了步骤5禁止指令重排

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容