JUC:4_2并发协作模型:生产者消费者问题:if虚假唤醒,防止虚假唤醒
线程之间的通信,如何交替执行?
线程A、B操作同一个变量numbe=0
/**
* 线程之间的通信,如何交替执行 ?
* 线程A、B操作同一个变量numbe=0
* A++
* B--
* <p>
* 问题:
* 1.在只有两个线程存在的情况是安全的,再多一个++的和一个--的
*/
public class TestCondition {
public static void main(String[] args) {
ServiceImpl service = new ServiceImpl();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
service.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
service.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
service.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
service.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "D").start();
}
}
class ServiceImpl {
private int number = 0;
//++
public synchronized void increment() throws InterruptedException {
// if (number != 0) {
while (number != 0) {
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName() + "===>" + number);
//通知其他线程++完毕
this.notifyAll();
}
//--
public synchronized void decrement() throws InterruptedException {
// if (number == 0) {
while (number == 0) {
//等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName() + "===>" + number);
//通知其他线程--完毕
this.notifyAll();
}
}
一个++一个–来操作
在只有两个线程++、–去操作,在只有两个线程存在的情况是安全的
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
两个++和两个–线程同时操作number
两个++和两个–线程同时操作number,都出现了负数
A===>1
B===>0
C===>1
A===>2
C===>3
B===>2
B===>1
B===>0
C===>1
A===>2
C===>3
B===>2
B===>1
B===>0
C===>1
D===>0
A===>1
D===>0
C===>1
B===>0
C===>1
D===>0
A===>1
D===>0
C===>1
B===>0
C===>1
D===>0
A===>1
D===>0
C===>1
B===>0
D===>-1
D===>-2
D===>-3
D===>-4
A===>-3
问题怎么出现的:if和while
怎么出现这种负数:
出现>1,消费者notiyall时,是另外一个正在wait的生产者抢到了锁,执行了++
出现<0,消费者notiyall时,是另外一个正在wait的消费者抢到了锁,执行了–
两个原因
- object的wait()方法会释放锁,与sleep抱着锁睡觉不同,释放锁之后,第二个线程就可以获取锁
- if只会判断一次,if判断,在if方法体没有执行完的情况下进入锁等待,等再次被唤醒重新时获取锁,不会再去做一次if判断,而是继续执行if里面的内容
if判断为空时,线程被阻塞,这时if判断就已经完成了,线程被唤醒会执行剩余操作
while判断为空时,线程被阻塞,这时while循环没有完成,线程被唤醒后会重新进行while判断
不用while自旋的话,如果多个消费者或者生产者会互相竞争共享资源
object的wait()为什么要用while来判断?
public final void wait() throws InterruptedException
导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法。 换句话说,这个方法的行为就好像简单地执行呼叫wait(0) 。
当前的线程必须拥有该对象的显示器。 该线程释放此监视器的所有权,并等待另一个线程通知等待该对象监视器的线程通过调用notify方法或notifyAll方法notifyAll 。 然后线程等待,直到它可以重新获得监视器的所有权并恢复执行。
像在一个参数版本中,中断和虚假唤醒是可能的,并且该方法应该始终在循环中使用:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}