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

Java 并发内存模型

作者: qingshuiting | 来源:发表于2018-10-05 10:31 被阅读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/gjtqaftx.html