【并发编程】Java内存模型

本文探讨了Java内存模型中的可见性问题,通过实例说明volatile关键字如何确保共享变量更新的可见性,以及与synchronized在原子性和可见性上的区别。同时,讨论了指令重排序对多线程程序正确性的影响。
摘要由CSDN通过智能技术生成

  

       📝个人主页:五敷有你      
 🔥系列专栏:并发编程
⛺️稳重求进,晒太阳

      这一章进一步深入学习共享变量在多线程间的【可见性】问题,与多条指令执行时的【有序性】问题

Java内存模型

JMM即Java Memory Model ,它定义了内存,工作内存的抽象概念,底层对应着CPU寄存器,缓存,硬件内存,CPU指令优化等。

JMM体现在如下几个方面

  • 原子性:保证指令不会受到线程上下文切换的影响
  • 可见性:保证指令不会收到CPU缓存的影响
  • 有序性:保证指令不会受CPU指令并行优化的影响

可见性

退不出的循环

先来看一个现象,main线程对run变量的修改对于t线程不可见,导致t线程无法停止

stat
static boolean run=true;
public static void main(String[] args) throws InterruptedException {
    Thread t1=new Thread(()->{
       while (run){
           //...一直运行
       }
    });
    t1.start();
    Thread.sleep(2000);
    run=false;
    log.debug("停止{}",run);



}

为什么呢?分析一下

初始状态,t线程刚开始从主存读取到run的值到工作内存

2 因为t线程要频繁主存中读取run的值,JIT编译器会将run的值缓存至自己的工作内存中的高速缓存中,。减少对主存中run的访问。提高效率

3、 1s后,mian线程修改了run的值,并同步至主存,而t是从自己工作内存中的高速缓存中读取这个变量的值,结果永远是旧的值

可见性解决方法

  1. volatile(易变关键字)

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

  1. synchorinzed

        某一个线程进入synchronized代码块前后,线程会加锁,清空工作内存,从主内存拷贝共享变量最新的值到工作区称为副本

        执行代码,将修改后的副本刷新回到主存中,线程释放锁

可见性VS原子性

        前面例子体现的是可见性,它保证的是在多个线程之间,一个线程对volatile变量的修改对另一个线程可见,不能保证原子性,仅用一个写线程,多个读线程的清空。

上例的字节码文件理解是这样的:

        比较一下,之前线程安全时举得例子:两个线程一个i++,一个i--,只能保证看到最新值,不能解决指令交错的问题。

        在下面,线程2读取值0 然后切换 线程1读取i的值, 之后准备常熟1 ,然后写回JMM,之后线程2 修改后写回JMM, 结果是-1,与期待不符,这是原子性问题,而volatile是解决的可见性的问题

        注意 synchronized 语句块既可以保证代码块的原子性,也同时保证代码块内变量的可见性。但缺点是synchronized 是属于重量级操作,性能相对更低

        如果在前面示例的死循环中加入 System.out.println() 会发现即使不加 volatile 修饰符,线程 t 也能正确看到对 run 变量的修改了,想一想为什么?

如下,在println中有synchronized

有序性

JVM会在不影响正确性的前提下,可以调整语句的执行顺序,思考下面的一段代码

static int i; static int j; //在某个线程内执行如下赋值操作 i=...; j=...;

可以看到,至于是先执行i,还是先执行j, 对最终结果不会产生影响,所以,上面的代码真正执行时,既可以是

i=...; j=...;

也可以是

i=...; j=...;

这种特性称之为指令重排序,在多线程下,【指令重排序】会影响正确性,为什么要有指令重排序这项优化呢?从CPU执行指令的原理来理解

---------【并发编程】指令集并行原理-CSDN博客

  • 27
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

五敷有你

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

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

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

打赏作者

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

抵扣说明:

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

余额充值