美文网首页
Java 并发内存模型

Java 并发内存模型

作者: qingshuiting | 来源:发表于2019-02-20 09:37 被阅读0次

Java 并发内存模型

并发中的问题

  • 指令重排

    • a=1; b=x; 在没有数据依赖,所以可能会先执行b=x;a=1
  • 内存可见性

    • 多线程在对同一个资源进行访问的时候,会因为缓存的原因导致内存可见性问题。在多核系统中,可能核可能有自己独占的缓存。
  • 原子性

synchronized关键字

进入synchronized:在进入synchronize以后,共享变量的缓存会失效,所以使用的时候需要从主内存中获取。

退出synchronized:在退出synchronize的时候,会将缓冲区(进入synchronize前或者在synchronize中修改的变量)的数据写入到主内存中。所以共享变量的修改对其他线程可见是在synchronize退出以后。

单例分析

public class Singleton {

    private static Singleton instance = null;

    private int v;
    private Singleton() {
        this.v = 3;
    }

    public static Singleton getInstance() {
        if (instance == null) { // 1. 第一次检查
            synchronized (Singleton.class) { // 2
                if (instance == null) { // 3. 第二次检查
                    instance = new Singleton(); // 4
                }
            }
        }
        return instance;
    }
}

模拟两个线程:线程A和线程B。线程A执行到instance = new Singleton()代码。这段代码的指令可以分解为两个部分:申请内存,并且使用构造方法初始化属性;然后把对象的引用赋值给instance。这两条只能可能会发生重新排序的。

如果线程B 这个时候执行到了if (instance == null) 那么有可能看到的instance不是null,因为有可能线程A在获得对象的引用之后,就马上把instance写回了主内存,然后线程B在第一行代码又从主内存中读取了新的instance值,发现instance不是null就马上返回了,但是这个时候线程B拿到的instance对象里面的属性可能是未初始化好的。

但是如果线程A 走出了synchronized代码块,那么instance一定是完整的内容。

volatile的使用

  • 内存可见性
  • 每次读取volatile变量的时候会从主内存中读取,写的时候会直接写会主内存
  • 指令重排
  • 单例中的instance赋值和构造函数的调用不会被重新排序

所以volatile的作用就非常明显了,如果我们需要多线程之间的变量具有立即可见性,就需要对变量使用volatile。

并且:由于long,double是64位的,但是java写入是32位32位的写入,所以鼓励使用volatile来进行

相关文章

网友评论

      本文标题:Java 并发内存模型

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