11# Java 多线程三大核心
22
33## 原子性
4- Java 的原子性就和数据库事物的原子性差不多,一个操作中要么全部执行成功或者失败。
4+ ` Java ` 的原子性就和数据库事物的原子性差不多,一个操作中要么全部执行成功或者失败。
55
66` JMM ` 只是保证了基本的原子性,但类似于 ` i++ ` 之类的操作,看似是原子操作,其实里面涉及到:
77
@@ -11,7 +11,7 @@ Java 的原子性就和数据库事物的原子性差不多,一个操作中要
1111
1212这三步操作,所以想要实现 ` i++ ` 这样的原子操作就需要用到 ` synchronize ` 或者是 ` lock ` 进行加锁处理。
1313
14- 如果是基础类的自增操作可以使用 ` AtomicInteger ` 这样的原子类来实现(其本质是利用了 CPU 级别的 的 ` CAS ` 指令来完成的)。
14+ 如果是基础类的自增操作可以使用 ` AtomicInteger ` 这样的原子类来实现(其本质是利用了 ` CPU ` 级别的 的 ` CAS ` 指令来完成的)。
1515
1616其中用的最多的方法就是: ` incrementAndGet() ` 以原子的方式自增。
1717源码如下:
@@ -46,7 +46,7 @@ public final boolean compareAndSet(long expect, long update) {
4646
4747## 可见性
4848
49- 现代计算机中,由于 ` CPU ` 直接从主内存中读取数据的效率不高,所以都会对应的 CPU 高速缓存,先将主内存中的数据读取到缓存中,线程修改数据之后首先更新到缓存,之后才会更新到主内存。如果此时还没有将数据更新到主内存其他的线程此时来读取就是修改之前的数据。
49+ 现代计算机中,由于 ` CPU ` 直接从主内存中读取数据的效率不高,所以都会对应的 ` CPU ` 高速缓存,先将主内存中的数据读取到缓存中,线程修改数据之后首先更新到缓存,之后才会更新到主内存。如果此时还没有将数据更新到主内存其他的线程此时来读取就是修改之前的数据。
5050
5151![ ] ( https://ws2.sinaimg.cn/large/006tKfTcly1fmouu3fpokj31ae0osjt1.jpg )
5252
@@ -81,7 +81,7 @@ Java 中可以使用 `volatile` 来保证顺序性,`synchronize 和 lock` 也
8181
8282#### 双重检查锁的单例模式
8383
84- 可以用 volatile 实现一个双重检查锁的单例模式:
84+ 可以用 ` volatile ` 实现一个双重检查锁的单例模式:
8585
8686``` java
8787public class Singleton {
@@ -101,14 +101,14 @@ public class Singleton{
101101}
102102```
103103
104- 这里的 volatile 关键字主要是为了防止指令重排。
105- 如果不用 volatile ,` singleton = new Singleton(); ` ,这段代码其实是分为三步:
104+ 这里的 ` volatile ` 关键字主要是为了防止指令重排。
105+ 如果不用 ` volatile ` ,` singleton = new Singleton(); ` ,这段代码其实是分为三步:
106106
107107- 分配内存空间。(1)
108108- 初始化对象。(2)
109109- 将 ` singleton ` 对象指向分配的内存地址。(3)
110110
111- 加上 volatile 是为了让以上的三步操作顺序执行,反之有可能第二步在第三步之前被执行就有可能某个线程拿到的单例对象是还没有初始化的,以致于报错。
111+ 加上 ` volatile ` 是为了让以上的三步操作顺序执行,反之有可能第二步在第三步之前被执行就有可能某个线程拿到的单例对象是还没有初始化的,以致于报错。
112112
113113#### 控制停止线程的标记
114114
@@ -132,7 +132,7 @@ private void stop(){
132132这里主要利用的是 ` volatile ` 的内存可见性。
133133
134134总结一下:
135- - volatile 关键字只能保证可见性,顺序性,** 不能保证原子性** 。
135+ - ` volatile ` 关键字只能保证可见性,顺序性,** 不能保证原子性** 。
136136
137137
138138
0 commit comments