美文网首页
使用volatile解决可见性与重排序问题

使用volatile解决可见性与重排序问题

作者: 砌月东谷 | 来源:发表于2021-07-02 07:15 被阅读0次

    不同线程直接进行数据交互时,会经理8个步骤:

    1. Lock 把主内存中的变量标识为一条线程独占状态
    2. Read 把主内存中的变量读取到工作内存中
    3. Load 把变量放入变量副本中
    4. Use 把变量副本传递给线程使用
    5. Assign 把线程正在使用的变量传递到工作内存中的变量副本
    6. Store 把工作内存中的变量副本传递到主内存中
    7. Write 把变量副本作为一个变量放入主内存中
    8. UnLock 解除线程的独占状态

    volatile是JVM提供的一个轻量级的同步机制,除了能够避免“JVM对long/double的误操作”外(JVM允许64位的long和double类型在执行load,store,read和write操作时,分成两次32位的原子性操作,这就意味着多个线程共享一个long或double类型时,某一个线程理论上可能读到半个long或double值,可以使用volatile关键字来避免jvm的误操作,但是目前主流的jvm都已经允许将64位的数据类型直接设置为原子性操作),还有以下两个作用

    1、volatile修饰的变量可以对所有线程立即可见

    不同线程如果要访问同一个变量,就必须借助主内存进行传递,但是如果个变量加了volatile关键字,则该变量的值就可以被所有线程即时感知,某一个线程对volatile变量进行的任何操作,都会在第一时间同步到其他线程中

    2、volatile可以禁止指令进行重排序优化

    真正意义上的单例模式

    public class Singeton {
        private volatile static Singeton instance=null;
        
        private Singeton(){}
        
        public static Singeton getInstance(){
            if(instance==null){
                synchronized (Singeton.class){
                    if(instance==null){
                        instance=new Singeton();
                    }
                }
            }
            return instance;
        }
    }
    

    此外,要特别注意的一点是,虽然volatile修饰的变量具有可见性,但是并不具备原子性,因此volatile不是线程安全的。要理解这点,就要明确区分原子性和重排序的概念:原子性是指某一条语句不可再拆分,重排序是指某一条语句内部的多个指令的执行顺序

    如果要实现线程安全,可以使用java.util.concurrent.atomic包中提供的原子类型,该类通过实现CAS算法保证了原子性操作。

    相关文章

      网友评论

          本文标题:使用volatile解决可见性与重排序问题

          本文链接:https://www.haomeiwen.com/subject/viceultx.html