hooyantsing's Blog

7_传统的生产者消费者问题,防止虚假唤醒

字数统计: 474阅读时长: 2 min
2020/08/24

7 传统的生产者消费者问题,防止虚假唤醒

狂神说Java JUC并发编程最新版通俗易懂

虚假唤醒

当使用 if 代码块内部含有 wait() 方法,线程被阻塞了,当被唤醒时并不会再次去判断是否需要被阻塞的条件,因此就直接向下执行了。

评论说:

用if判断的话,唤醒后线程会从wait之后的代码开始运行,但是不会重新判断if条件,直接继续运行if代码块之后的代码,而如果使用while的话,也会从wait之后的代码运行,但是唤醒后会重新判断循环条件,如果不成立再执行while代码块之后的代码块,成立的话继续wait。

JDK手册

JDK 手册要求使用 while 来放 wait() 方法。

81c743c98f2c860708d46b0d04c14b15.png

案例

生产者和消费者案例,使用 while 解决虚假唤醒的问题。

资源 解耦出来,降低程序耦合性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package demo1;

public class PC {
public static void main(String[] args) {
Date date = new Date();
new Thread(
() -> {
try {
for (int i = 0; i < 10; i++) {
date.increment();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A"
).start();

new Thread(
() -> {
try {
for (int i = 0; i < 10; i++) {
date.decrement();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
},"B"
).start();

new Thread(
() -> {
try {
for (int i = 0; i < 10; i++) {
date.increment();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
},"C"
).start();

new Thread(
() -> {
try {
for (int i = 0; i < 10; i++) {
date.decrement();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
},"D"
).start();
}
}

class Date {
private int number = 1;

public synchronized void increment() throws InterruptedException {
while (number != 0){
this.wait();
}
number++;
System.out.println("生产者" + Thread.currentThread().getName() + "-->" + number);
this.notifyAll();
}

public synchronized void decrement() throws InterruptedException {
while (number == 0){
this.wait();
}
number--;
System.out.println("消费者" + Thread.currentThread().getName() + "-->" + number);
this.notifyAll();
}
}

运行结果:

ca24926c24ac8d9fa403cc214e56b7a3.png

CATALOG
  1. 1. 7 传统的生产者消费者问题,防止虚假唤醒
    1. 1.1. 虚假唤醒
      1. 1.1.1. JDK手册
      2. 1.1.2. 案例