主内存的数据会被加载到cpu本地缓存里去,cpu后面会读写自己的缓存

缓存模型下的并发问题

java内存模型

read(从主存读取),load(将主存读取到的值写入工作内存),use(从工作内存读取数据来计算),assign(将计算好的值重新赋值到工作内存中),store(将工作内存数据写入主存),write(将store过去的变量值赋值给主存中的变量)

volatile保持内存可见的原理

就是说一定会强制保证说assign之后,就立马执行store + write,刷回到主内存里去。并且将其他工作内存中的状态改为过期

volatile无法保持原子性的原理

2个线程同时use后,线程1assign了以后,刷回了主内存。但线程2已经use了,不需要在从内存中加载。此时使用的旧的值。

底层使用cpu的MESI缓存一致性协议,强制刷主内存,过期其他线程中的工作内存

volatile内存屏障及happen before原则

在被volatile标记的字段读写前后都设置内存屏障,防止指令重排。

指令重排的happen before原则,是给开发JVM的人看的。

大概有几个原则

程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作

lock规则:一个unLock操作先行发生于后面对同一个锁的lock操作

volatile变量规则:必须保证是先写,再读

volatile的实际用途和场景

double check的单例模式,使用volatile防止指令重排

instance=new Singleton() 分为3步

1、volatile保证并发可见性

2、synchronized保证有序性

3、double check保证对象被正常创建(类加载创建过程多线程问题)

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