无名之辈

基础篇:深入JMM内存模型volatile、synchroniz

2020-07-16  本文已影响0人  潜行前行

先介绍下多进程多线程在linux几种通信方式

<font color='red'>java设计上则是基于共享内存来实现进程,线程的通信</font>

1 java内存模型,JMM(JAVA Memory Model)

image

2 CPU高速缓存、MESI协议

3 指令重排序和内存屏障指令

JAVA内存屏障指令 作用描述
Store1;StoreStore;Store2 确保Store1数据对其他处理器可见(刷新到内存),先于Store2及所有后续存储指令的存储。
Load1;LoadStore;Store2 确保Load1数据装载先于Store2及所有后续存储指令的存储。
Store1;StoreLoad;Load2 确保Store1数据对其他处理器可见(刷新到内存)先于Load2及所有后续装载指令的装载。
Load1;LoadLoad;Load2 确保Load1数据的装载,先于Load2及所有后续装载指令的装载。

特殊的是StoreLoad,会使该屏障之前的所有内存访问指令(装载和存储指令)完成之后,才执行该屏障之后的内存访问指令;是一个”全能型”的屏障,它同时具有其他三个屏障的效果

4 happen-before原则

5 synchronized内存语义

class Count{
    int a = 0;
    public synchronized void writer(){// 1 
        a++; //2
    } //3
    public synchronized void reader(){// 4 
        int i = a; //5 
    } //6
}
image

6 volatile的内存语义

volatile Object instance;
instance = new Object();
//相应汇编代码
0x01a3de1d: movb $0×0,0×1104800(%esi);0x01a3de24: lock addl $0×0,(%esp);
int a = 0; volatile boolean v = false;

线程A
a = 1;    //1 
v = true; //2

线程B
v = true; //3
System.out.println(a);//4  
image

7 final内存语义

8 synchronized,volatile内存语义的原理梳理

image

9 练习题:延迟加载双重锁定是否真的安全

public class Instance {                         // 1
    private static Instance instance;           // 2
    public static Instance getInstance() {      // 3
        if (instance == null) {                 // 4:第一次检查
            synchronized (Instance.class) {     // 5:加锁
                if (instance == null)           // 6:第二次检查
                    instance = new Instance();  // 7:问题的根源出在这里
            }                                   // 8
        }                                       // 9
        return instance;                        // 10
    }                                           // 11
}

代码第7行instance=new Singleton();创建了一个对象。这一行代码可以分解为如下的3行伪代码

memory = allocate(); // A1:分配对象的内存空间 
ctorInstance(memory); // A2:初始化对象 
instance = memory; // A3:设置instance指向刚分配的内存地址

假如2和3之间重排序之后的顺序如下

memory = allocate(); // A1:分配对象的内存空间 
instance = memory;  //A3:instance指向刚分配的内存地址,此时对象还没有被初始化
ctorInstance(memory); // A2:初始化对象

假如发生A3、A2重排序,线程是不保障赋值初始化对象两步骤操作结果会一起同步到主存。

<font color='red'>因此第二个线程执行到if (instance == null);// 4:第一次检查时,可能会得到一个刚分配的内存而没初始化的对象(此时没有加锁,锁的happens-before规则不适用)</font>

10 练习题:伪共享(false sharing)

image image

参考文章

上一篇 下一篇

猜你喜欢

热点阅读