并发-JAVA内存模型解析及volatile原理

Java Memory Model(Java内存模型)

JMM定义了主存(所有线程都共享的数据)和工作内存(每个线程都私有的数据)抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等

体现如下:

  • 原子性 - 保证指令不会受到上下文切换的影响
    • Monitor主要关注的就是访问共享变量时,保证临界区代码的原子性
  • 可见性 - 保证指令不会受到cpu缓存的影响
  • 有序性 - 保证指令不会受到cpu执行并行优化的影响

可见性

一个线程对主存中的数据进行了修改,对于另一个线程不可见(可能是另一个线程有缓存)就导致了可见性问题

volatile(易变关键字)

它用来修饰成员变量和静态成员变量,他可以避免线程从自己的工作缓存中查找该变量的值,必须到主存中获取它的值,线程操作volatile变量都是直接操作主存,解决可见性问题

public volatile staic boolean flag1 = true;
private volatile boolean flag2 = true;

用synchronized加锁也可以解决可见性问题,但是volatile更轻量

有序性

JVM会在不影响正确性的前提下,可以调整语句的执行顺序

这种特性称为指令重排,多线程下的指令重排会影响正确性

volatile也可以解决重排序问题

volatile原理

volatile的底层实现原理是内存屏障,Memory Barrier(Memory Fence)

  • 对volatile变量的写指令后会加入写屏障
  • 对volatile变量的读指令前会加入读屏障

写屏障(sfence)保证在该屏障之后,对共享变量的改动,都同步到主存中(保证可见性)

还会确保指令重排时,不会将写屏障之前的代码排在写屏障之后(保证有序性)

volatile static boolean ready = false;
public void actor1(I_Result r){
    num = 2;
    ready = true; // ready是volatile赋值带写屏障
    // 写屏障
}

读屏障(lfence)保证在该屏障之后,对共享变量的读取,加载的是主存中的最新数据(保证可见性 )

还会确保指令重排时,不会将读屏障之后的代码排在读屏障之前(保证有序性)

public void actor2(I_Result r){
	// 读屏障
    if(ready){// ready是volatile修饰带读屏障
        r.r1 = num + num;
    }else{
        r.r1 = 1;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涛堆堆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值