1、代码实现
//生产者消费者问题
//等待->业务->通知唤醒
public class Mytest04 {
public static void main(String[] args) {
Resource resource = new Resource();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
resource.increase();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"生产者1").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
resource.decrease();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"消费者1").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
resource.increase();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"生产者2").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
resource.decrease();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"消费者2").start();
}
}
//资源文件
class Resource{
private int number = 0;
public synchronized void increase() throws InterruptedException {
if(number !=0){
//等待
this.wait();
}
//业务
number++;
System.out.println(Thread.currentThread().getName()+"->"+number);
//通知
this.notifyAll();
}
public synchronized void decrease() throws InterruptedException {
if (number == 0){
//等待
this.wait();
}
//业务
number--;
System.out.println(Thread.currentThread().getName()+"->"+number);
//通知
this.notifyAll();
}
}
输出:
生产者1->1
消费者1->0
生产者1->1
消费者1->0
生产者2->1
生产者1->2
生产者2->3
消费者1->2
消费者1->1
消费者1->0
生产者2->1
生产者1->2
生产者2->3
消费者2->2
消费者2->1
消费者2->0
生产者2->1
生产者1->2
消费者2->1
消费者2->0
//理想状态:值只有产品值只有0,1两个值,生产一件就消费一件
2、什么叫虚假唤醒
站在上述两个消费者线程的角度上讲, 无论哪一个线程抢到了资源, 另一个线程的唤醒就可以被认为是没有必要的, 也就是被虚假唤醒了。
3、原因与解决方式
上述代码使用if
判断,唤醒后线程会从wait
之后的代码开始运行,但是不会重新判断if条件,直接继续运行if代码块之后的代码,而如果使用while的话,也会从wait之后的代码运行,但是唤醒后会重新判断循环条件,如果不成立再执行while代码块之后的代码块,成立的话继续wait。
解决:将if
改为while