Skip to content

Commit ca059a5

Browse files
committed
更新线程通信
1 parent a5f392d commit ca059a5

File tree

2 files changed

+233
-0
lines changed

2 files changed

+233
-0
lines changed
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
package com.javaedge.concurrency.common.communication;
2+
3+
import java.util.concurrent.locks.LockSupport;
4+
5+
import org.testng.annotations.Test;
6+
7+
/**
8+
* 三种线程协作通信的方式:suspend/resume、wait/notify、park/unpark
9+
*
10+
* @author JavaEdge
11+
* @date 2019/10/8
12+
*/
13+
public class ThreadCommunication {
14+
15+
/**
16+
* 包子店
17+
*/
18+
public static Object bunShop = null;
19+
20+
/**
21+
* 正常的suspend/resume
22+
*/
23+
@Test
24+
public void suspendResumeTest() throws Exception {
25+
// 启动线程
26+
Thread consumerThread = new Thread(() -> {
27+
if (bunShop == null) {
28+
// 没包子,则进入等待
29+
System.out.println("1、进入等待");
30+
Thread.currentThread().suspend();
31+
}
32+
System.out.println("2、买到包子,回家");
33+
});
34+
consumerThread.start();
35+
// 3秒之后,生产一个包子
36+
Thread.sleep(3000L);
37+
bunShop = new Object();
38+
consumerThread.resume();
39+
System.out.println("3、通知消费者");
40+
}
41+
42+
/**
43+
* 死锁的suspend/resume。 suspend并不会像wait一样释放锁,容易写出死锁代码
44+
*/
45+
@Test
46+
public void suspendResumeDeadLockTest() throws Exception {
47+
// 启动线程
48+
Thread consumerThread = new Thread(() -> {
49+
if (bunShop == null) {
50+
// 没包子,则进入等待
51+
System.out.println("1、进入等待");
52+
// 当前线程拿到锁,然后挂起
53+
synchronized (this) {
54+
Thread.currentThread().suspend();
55+
}
56+
}
57+
System.out.println("2、买到包子,回家");
58+
});
59+
consumerThread.start();
60+
// 3秒之后,生产一个包子
61+
Thread.sleep(3000L);
62+
bunShop = new Object();
63+
// 争取到锁以后,再恢复consumerThread
64+
synchronized (this) {
65+
consumerThread.resume();
66+
}
67+
System.out.println("3、通知消费者");
68+
}
69+
70+
/**
71+
* 导致程序永久挂起的suspend/resume
72+
*/
73+
@Test
74+
public void suspendResumeDeadLockTest2() throws Exception {
75+
// 启动线程
76+
Thread consumerThread = new Thread(() -> {
77+
if (bunShop == null) {
78+
System.out.println("1、没包子,进入等待");
79+
try { // 为这个线程加上一点延时
80+
Thread.sleep(5000L);
81+
} catch (InterruptedException e) {
82+
e.printStackTrace();
83+
}
84+
// 这里的挂起执行在resume后面
85+
Thread.currentThread().suspend();
86+
}
87+
System.out.println("2、买到包子,回家");
88+
});
89+
consumerThread.start();
90+
// 3秒之后,生产一个包子
91+
Thread.sleep(3000L);
92+
bunShop = new Object();
93+
consumerThread.resume();
94+
System.out.println("3、通知消费者");
95+
consumerThread.join();
96+
}
97+
98+
/**
99+
* 正常的wait/notify
100+
*/
101+
@Test
102+
public void waitNotifyTest() throws Exception {
103+
// 启动消费者线程
104+
new Thread(() -> {
105+
if (bunShop == null) {
106+
// 如果没包子,则进入等待
107+
synchronized (this) {
108+
try {
109+
System.out.println("1、进入等待");
110+
this.wait();
111+
} catch (InterruptedException e) {
112+
e.printStackTrace();
113+
}
114+
}
115+
}
116+
System.out.println("2、买到包子,回家");
117+
}).start();
118+
// 3秒之后,生产一个包子
119+
Thread.sleep(3000L);
120+
bunShop = new Object();
121+
synchronized (this) {
122+
this.notifyAll();
123+
System.out.println("3、通知消费者");
124+
}
125+
}
126+
127+
/**
128+
* 会导致程序永久等待的wait/notify
129+
*/
130+
@Test
131+
public void waitNotifyDeadLockTest() throws Exception {
132+
// 启动线程
133+
new Thread(() -> {
134+
if (bunShop == null) { // 如果没包子,则进入等待
135+
try {
136+
Thread.sleep(5000L);
137+
} catch (InterruptedException e1) {
138+
e1.printStackTrace();
139+
}
140+
synchronized (this) {
141+
try {
142+
System.out.println("1、进入等待");
143+
this.wait();
144+
} catch (InterruptedException e) {
145+
e.printStackTrace();
146+
}
147+
}
148+
}
149+
System.out.println("2、买到包子,回家");
150+
}).start();
151+
// 3秒之后,生产一个包子
152+
Thread.sleep(3000L);
153+
bunShop = new Object();
154+
synchronized (this) {
155+
this.notifyAll();
156+
System.out.println("3、通知消费者");
157+
}
158+
}
159+
160+
/**
161+
* 正常的park/unpark
162+
*/
163+
@Test
164+
public void parkUnparkTest() throws Exception {
165+
// 启动线程
166+
Thread consumerThread = new Thread(() -> {
167+
if (bunShop == null) { // 如果没包子,则进入等待
168+
System.out.println("1、进入等待");
169+
LockSupport.park();
170+
}
171+
System.out.println("2、买到包子,回家");
172+
});
173+
consumerThread.start();
174+
// 3秒之后,生产一个包子
175+
Thread.sleep(3000L);
176+
bunShop = new Object();
177+
LockSupport.unpark(consumerThread);
178+
System.out.println("3、通知消费者");
179+
}
180+
181+
/**
182+
* 死锁的park/unpark
183+
*/
184+
@Test
185+
public void parkUnparkDeadLockTest() throws Exception {
186+
// 启动线程
187+
Thread consumerThread = new Thread(() -> {
188+
if (bunShop == null) { // 如果没包子,则进入等待
189+
System.out.println("1、进入等待");
190+
// 当前线程拿到锁,然后挂起
191+
synchronized (this) {
192+
LockSupport.park();
193+
}
194+
}
195+
System.out.println("2、买到包子,回家");
196+
});
197+
consumerThread.start();
198+
// 3秒之后,生产一个包子
199+
Thread.sleep(3000L);
200+
bunShop = new Object();
201+
// 争取到锁以后,再恢复consumerThread
202+
synchronized (this) {
203+
LockSupport.unpark(consumerThread);
204+
}
205+
System.out.println("3、通知消费者");
206+
}
207+
208+
public static void main(String[] args) throws Exception {
209+
// 对调用顺序有要求,也要开发自己注意锁的释放。这个被弃用的API, 容易死锁,也容易导致永久挂起。
210+
// new Demo6().suspendResumeTest();
211+
// new Demo6().suspendResumeDeadLockTest();
212+
// new Demo6().suspendResumeDeadLockTest2();
213+
214+
// wait/notify要求再同步关键字里面使用,免去了死锁的困扰,但是一定要先调用wait,再调用notify,否则永久等待了
215+
// new Demo6().waitNotifyTest();
216+
// new Demo6().waitNotifyDeadLockTest();
217+
218+
// park/unpark没有顺序要求,但是park并不会释放锁,所有再同步代码中使用要注意
219+
// new Demo6().parkUnparkTest();
220+
// new Demo6().parkUnparkDeadLockTest();
221+
222+
}
223+
}

pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,16 @@
8484
<artifactId>spring-rabbit</artifactId>
8585
<version>2.1.4.RELEASE</version>
8686
</dependency>
87+
<dependency>
88+
<groupId>org.springframework.boot</groupId>
89+
<artifactId>spring-boot-test</artifactId>
90+
</dependency>
91+
<dependency>
92+
<groupId>org.testng</groupId>
93+
<artifactId>testng</artifactId>
94+
<version>7.0.0-beta3</version>
95+
<scope>compile</scope>
96+
</dependency>
8797

8898
</dependencies>
8999

0 commit comments

Comments
 (0)