JMM详解:三大特征

12/31/2023 Java

目录


参考:


# JMM的三大特征

整个 JMM 实际上是围绕着三个特征建立起来的。分别是:原子性,可见性,有序性。这三个特征可谓是整个 Java 并发的基础。


# 原子性

原子性指的是一个操作是不可分割,不可中断的,一个线程在执行时不会被其他线程干扰。

原子性:一个或多个操作,要么全部执行,要么全部不执行(执行的过程中是不会被任何因素打断的)。

我们来看下面的代码:

int i = 2;
int j = i;
i++;
i = i + 1;
1
2
3
4

上面这几句代码能保证原子性吗?

  • 第一句是基本类型赋值操作,必定是原子性操作。
  • 第二句先读取 i 的值,再赋值到 j,两步操作,不能保证原子性。
  • 第三和第四句其实是等效的,先读取 i 的值,再 +1,最后赋值到 i,三步操作了,不能保证原子性。

JMM 只能保证基本的原子性,如果要保证一个代码块的原子性,提供了 monitorentermoniterexit 两个字节码指令,也就是 synchronized 关键字。因此synchronized 块之间的操作都是原子性的


# 可见性

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

可见性:只要有一个线程对共享变量的值做了修改,其他线程都将马上收到通知,立即获得最新值。

Java 是利用 volatile 关键字来提供可见性的。 当变量被volatile 修饰时,这个变量被修改后会立刻刷新到主内存,当其它线程需要读取该变量时,会去主内存中读取新值。而普通变量则不能保证这一点。

除了 volatile 关键字之外,finalsynchronized也能实现可见性。

  • synchronized 的原理是,在执行完,进入 unlock 之前,必须将共享变量同步到主内存中。
  • final 修饰的字段,一旦初始化完成,如果没有对象逸出(指对象为初始化完成就可以被别的线程使用),那么对于其他线程都是可见的。

# 有序性

有序性: 有序性可以总结为:在本线程内观察,所有的操作都是有序的;而在一个线程内观察另一个线程,所有操作都是无序的。

在 Java 中,可以使用 synchronized 或者 volatile 保证多线程之间操作的有序性。实现原理有些区别:

  • volatile关键字是使用内存屏障达到禁止指令重排序,以保证有序性。
  • synchronized的原理是,一个线程 lock 之后,必须 unlock后,其他线程才可以重新lock,使得被 synchronized包住的代码块在多线程之间是串行执行的。
上次更新时间: 9/25/2024, 9:17:45 AM