美文网首页
使用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