1.保障线程对主存中该数据的可见性

 当修改了增加volatile 的变量时,会马上将变量值写回到主内存中,这时会在store 前对主内存的这个变量加锁,在store 通过总线的时候触发MESI缓存一致性协议,通过总线嗅探器将其他cpu工作内存中缓存该变量的行设置为无效。当cpu 完成变量的write 操作时,再对变量进行解锁。

2.不保证原子性

当线程A对工作内存中的i进行自增的时候,i+1

  1. 从主存中读取i
  2. i+1
  3. 写入主存

当执行第2的时候,变量i并未回到主存中,所以变量未加锁,这时线程B拿到i也进行自增,问题就在这,线程A中变量i的操作还未全部完成,线程B就已经拿到i了,这就违背了原子性的定义——要么成功,要么失败。所以为什么要使用

3.保证有序性

拿单例模式——懒汉式举例,为什么单例对象要加volatile

class Singleton {
    //懒汉式
    private volatile static Singleton singleton;

    public static Singleton getInstance(String i) {

        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }

}

Object obj=new Object();

  1. memory=allocate()  //分配内存空间
  2. obj(memory)  //初始化对象
  3. obj=memory  //设置obj指向分配的内存地址,此时obj不为bull

一个理想中对象的实例化顺序是以上3步,但是编译器在优化的时候可能会打乱顺序,应该不会影响最终结果——实例化。

问题就在实例化的过程中,顺序打算为1-3-2,当另一个线程在执行到3也就是还未初始化对象的时候拿这个对象的实例进行操作就会出现问题。

 

 

 

Rick  32浏览  0评论  2020-09-26

上一篇