JMM中的原子性、可见性、有序性和volatile关键字

本文详细讲解了Java内存模型(JMM)中的原子性、可见性和有序性,并重点分析了volatile关键字的作用,包括确保可见性和禁止指令重排序。文章通过实例阐述了这些问题,并提到了volatile在多线程并发编程中的应用及其底层实现机制。
摘要由CSDN通过智能技术生成

相信如果对JMM底层有过了解或者接触过java并发编程的读者对以上的概念并不陌生,但是真正理解的可能并不多。这里我就对这些概念再做一次讲解。相信读者多读几遍应该就有自己的理解,实在不理解也没关系,说明知识的储备还不够,不妨以后再来读一遍,可能会瞬间突然明白。

参考内容:

  1. https://mp.weixin.qq.com/s/kQ498ifh4OUEDd829JIhnQ 作者:CodeSheep;他同时也是B站up主,ID就是CodeSheep,视频良心,有兴趣的读者可以自己查看。
  2. 《实战Java高并发程序设计》 作者:葛一鸣 郭超 ;如果是并发编程初学者我也推荐这本书,通俗易懂

JMM的关键技术点都是围绕着多线程的原子性、可见性和有序性来建立的。要理解JMM首先就需要了解这三个特性。而volatile关键字很好的贯彻了可见性和有序性,提到volatile关键字也是为了加深对这三个特性的理解,同时volatile也是非常重要的内容,也是难点。

1、原子性

原子性其实非常好理解,原子性操作就是指这些操作是不可中断的,要做一定做完,要么就没有执行,也就是不可被中断。

我们使用的int类型的数据如果只是是简单的读取和赋值的话就是原子操作。下面给出几个例子:

i = 2; 赋值给i  -----------------------------操作步骤:1  原子操作
j = i; 读取i值 赋值给j -----------------------操作步骤:2  非原子操作
i++; 读取i值 i值加1 赋值给i  ------------------操作步骤:3  非原子操作
i = i+1; 读取i值 i值加1 赋值给i  --------------操作步骤:3  非原子操作

但是如果我们不使用int型而使用long型的话,对于32位系统来说,long型数据的读写不是原子性的(因为long有64位)。虚拟机规范中允许对 64位数据类型( long和 double),分为 2次 32为的操作来处理,也就是说,如果两个线程同时对long进行写入的话(或者读取),对线程之间的结果是有干扰的。可能高位是一个线程写的,低位又是另一个线程写的,如果这时候读的话,就会读到错误的值。不是线程1写的值,也不是线程2写的值。但是最新 JDK实现还是实现了原子操作的。JMM只实现了基本的原子性,像上面 i++那样的操作,必须借助于 synchronized和 Lock来保证整块代码的原子性了。

2、可见性

可见性是指当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道这个修改。

显然,对于串行程序来说,可见性问题是不存在的。因为你在任何一个操作步骤中修改了某个变量,那么在后续的步骤中,读取这个变量的值,一定是修改后的新值。但是这个问题在并行程序中就不见得了。如果一个线程修改了某一个全局变量,那么其他线程未必可以马上知道这个改动。这个问题可能由cache优化引起,比如下面这个例子:

如果在CPU1和CPU2上各运行了一个线程,它们共享变量t,由于编译器优化或者硬件优化的缘故,在CPU1上的线程将变量t进行了优化,将其缓存在cache中或者寄存器里。这种情况下,如果在CPU2上的某个线程修改了变量t的实际值,那么CPU1上的线程可能并无法意识到这个改动,依然会读取cache中或者寄存器里的数据。因此,就产生了可见性问题。外在表现为:变量t的值被修改,但是CPU1上的线程依然会读到一个旧值。可见性问题也是并行程序开发中需要重点关注的问题之一。

可见性问题是一个综合性问题。除了上述提到的缓存优化或者硬件优化(有些内存读写可能不会立即触发,而会先进入一个硬件队列等待)会导致可见性问题外,指令重排(这个问题将在下一节中更详细讨论)以及编辑器的优化,都有可能导致一个线程的修改不会立即被其他线程察觉。

3、有序性

JMM是允许编译器和处理器对指令重排序的,但是规定了 as-if-serial语义,即不管怎么重排序,程序的执行结果不能改变。比如下面的程序段:

double pi = 3.14; // A
double r = 1; // B
doubles = pi *r *r; // C

无论是 A->B->C 还是 B->A->C 都对结果没有影响。但是这是发生在单线程之中的。在多线程之中可能就不是这样了,多线程有序性引起的问题我们可以看一个典型的例子:

class OrderExample{
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值