package com.lyon.juc;
/**
* 线程之间的通讯问题:生产者与消费者问题! 等待唤醒,通知唤醒
* 线程交替执行 A B 操作同一变量 num = 0
* A num+1
* B num-1
*/
public class A {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//判断是否需要等待 业务 通知
class Data{ //资源类
private int num = 0;
//+1
public synchronized void increment() throws InterruptedException {
//if(num!=0){ //虚假唤醒 只有A、B线程的时候,可使用if
//if(num!=0)判断是否需要生产或消费,num只能为1或者0,如果只有一个生产者,一个消费者,是没有问题的。
//如果现在有A,C两个生产者,A在进行了一次if判断后,进入了wait(),之后C进行了一次if判断后,也进入了wait()
//然后消费者B调用了notifyAll(),唤醒了A,C两个生产者,假设生产者A拿到锁,进行生产后num=1并释放锁,
//此时由于多线程调度问题,消费者B没有来消费,但是生产者C却被调度到了,问题就发生在这里。
//生产者B在执行wait()之前已经进行了if()判断,因此,生产者B会直接开始生产number=2
//问题就这么发生了,生产者B是不应该被唤醒的,或者说,因为生产者A已经生产了,即使生产者B被唤醒,也不应该直接去生产,而是应该观察一下自己需要真的需要去生产。
//如何解决?
//只需要将if()换做while()即可,这样一来,生产者B即使被唤醒了,本身还处于while()循环之中,如果不需要生产,那么会继续wait()下去
while(num!=0){
//等待
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName()+"=>"+num);
//通知其他线程,我+1完毕了
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
//if(num==0){ //虚假唤醒 只有A、B线程的时候,可使用if
while(num==0){
//等待
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName()+"=>"+num);
//通知其他线程,我-1完毕了
this.notifyAll();
}
}
|