Skip to content

Commit 7ef1929

Browse files
authored
Merge pull request crossoverJie#3 from crossoverJie/fix
new features: wait notify mechanism
2 parents 2dcdfaa + 3a2be9e commit 7ef1929

File tree

3 files changed

+111
-8
lines changed

3 files changed

+111
-8
lines changed

MD/Threadcore.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
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
8787
public 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

src/main/java/com/crossoverjie/actual/TwoThread.java

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
/**
77
* Function: 两个线程交替执行打印 1~100
88
*
9+
* lock 版
10+
*
911
* @author crossoverJie
1012
* Date: 11/02/2018 10:04
1113
* @since JDK 1.8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.crossoverjie.actual;
2+
3+
/**
4+
* Function:两个线程交替执行打印 1~100
5+
* 等待通知机制版
6+
*
7+
* @author crossoverJie
8+
* Date: 07/03/2018 13:19
9+
* @since JDK 1.8
10+
*/
11+
public class TwoThreadWaitNotify {
12+
13+
private int start = 1;
14+
15+
private boolean flag = false;
16+
17+
public static void main(String[] args) {
18+
TwoThreadWaitNotify twoThread = new TwoThreadWaitNotify();
19+
20+
Thread t1 = new Thread(new OuNum(twoThread));
21+
t1.setName("t1");
22+
23+
24+
Thread t2 = new Thread(new JiNum(twoThread));
25+
t2.setName("t2");
26+
27+
t1.start();
28+
t2.start();
29+
}
30+
31+
/**
32+
* 偶数线程
33+
*/
34+
public static class OuNum implements Runnable {
35+
private TwoThreadWaitNotify number;
36+
37+
public OuNum(TwoThreadWaitNotify number) {
38+
this.number = number;
39+
}
40+
41+
@Override
42+
public void run() {
43+
44+
while (number.start <= 100) {
45+
synchronized (TwoThreadWaitNotify.class) {
46+
System.out.println("偶数线程抢到锁了");
47+
if (number.flag) {
48+
System.out.println(Thread.currentThread().getName() + "+-+偶数" + number.start);
49+
number.start++;
50+
51+
number.flag = false;
52+
TwoThreadWaitNotify.class.notify();
53+
54+
}else {
55+
try {
56+
TwoThreadWaitNotify.class.wait();
57+
} catch (InterruptedException e) {
58+
e.printStackTrace();
59+
}
60+
}
61+
}
62+
63+
}
64+
}
65+
}
66+
67+
68+
/**
69+
* 奇数线程
70+
*/
71+
public static class JiNum implements Runnable {
72+
private TwoThreadWaitNotify number;
73+
74+
public JiNum(TwoThreadWaitNotify number) {
75+
this.number = number;
76+
}
77+
78+
@Override
79+
public void run() {
80+
while (number.start <= 100) {
81+
synchronized (TwoThreadWaitNotify.class) {
82+
System.out.println("奇数线程抢到锁了");
83+
if (!number.flag) {
84+
System.out.println(Thread.currentThread().getName() + "+-+奇数" + number.start);
85+
number.start++;
86+
87+
number.flag = true;
88+
89+
TwoThreadWaitNotify.class.notify();
90+
}else {
91+
try {
92+
TwoThreadWaitNotify.class.wait();
93+
} catch (InterruptedException e) {
94+
e.printStackTrace();
95+
}
96+
}
97+
}
98+
}
99+
}
100+
}
101+
}

0 commit comments

Comments
 (0)