JMM理解( 二 )
原子性
原子性是指一个操作是不可分割、不可中断的 , 要么全部执行成功要么全部执行失败 。
JMM 只能保证对基本数据类型的变量的读写操作是原子性的 , 但 long 和 double 除外(long 和 double 的非原子性协定) 。
我们来看看下面的例子:
int x = 1;
int y = x;
x ++;
上面三行代码只有第一行是原子性操作 , 基本类型赋值操作 , 必定是原子性操作 。
第二行代码先读取 x 变量的值 , 再进行赋值给 y 变量 , 进行了两个操作 , 不能保证原子性 。
第三行代码先读取 x 变量的值 , 再进行加 1 , 最后再赋值给 x 变量 , 进行了三个操作 , 不能保证原子性 。
在并发环境下 , 为了保证原子性 , Java 提供了 synchronized 关键字 。 因此在 synchronized 修饰的代码块之间的操作都是原子性的 。
【JMM理解】可见性
可见性是指所有线程都能看到共享内存的最新状态 。 即当一个线程修改了一个共享变量的值时 , 其他线程能够立即看到该变量的最新值 。
对于可见性问题 , Java 是提供了一个 volatile 关键字来保证可见性 。 当一个共享变量被 volatile 关键字修饰时 , 这个变量被修改后会立即刷新到主内存 , 保证其他线程看到的值一定是最新的 。
除了 volatile 关键字之外 , final 和 synchronized 也能实现可见性 。
final 关键字修饰的变量 , 在构造器中一旦初始化完成 , 如果没有对象逸出(指对象没有初始化完成就可以被别的线程使用) , 那么其他线程都就可以看见 final 修饰的变量 。
synchronized 的原理是 , 线程进入 synchronized 代码块后 , 线程会获取到 lock , 将会清空本地内存 , 然后从主内存中拷贝共享变量的最新值到本地内存作为副本 , 执行代码 , 又将修改后的副本值刷新到主内存中 , 最后线程执行 unlock 。
有序性
有序性是指程序执行的顺序按照代码的先后顺序执行 。
在 Java 中 , 可以通过 volatile 和 synchronized 关键字来保证多线程之间操作的有序性 。
volatile 关键字是通过在主存中加入内存屏障来达到禁止指令重排序 , 来保证有序性 。
synchronized 关键字原理是 , 一个变量在同一时刻只能被一个线程 lock , 并且必须 unlock 后 , 其他线程才可以重新 lock , 使得被 synchronized 修饰的代码块在多线程之间是串行执行的 。
- 数据|新基建时代,高大全的数据管理解决方案是怎样“炼”成的?
- 深入理解Netty编解码、粘包拆包、心跳机制
- 不被理解的超时代发明,你知道几个?在线膜拜大神,西瓜视频真相
- 《深入理解Java虚拟机》:Java内存区域
- 彻底理解 IO 多路复用实现机制
- 《深入理解Java虚拟机》:线程安全,两种同步锁实现
- 输出层|PyTorch可视化理解卷积神经网络
- RFID在冷链物流中的作用-RFID冷链资产管理解决方案
- 研究池|用户在线评论中的商业情报:理解消费者感知及影响因素
- Flink中parallelism并行度和slot槽位的理解