生产者消费者问题、防止虚假唤醒
传统synchronized
package JUC;
/**
* Copyright © 2021 eSunny Info. Tech Ltd. All rights reserved.
*
* 功能描述:生产者
* 操作同一个变量 通知等待唤醒
* Provider num + 1
* Consumer num - 1
*/
public class ProviderConsumer {
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();
}
}
class Data{
//数字 资源类
private int number = 0;
// +1
public synchronized void increment() throws InterruptedException {
if (number!=0) {
//等待减少
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName() + "票数加 +"+ number);
//通知
this.notifyAll();
}
// -1
public synchronized void decrement() throws InterruptedException {
if (number==0) {
//等待增加
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName() + "票数减 -"+ number);
//通知
this.notifyAll();
}
}
2个线程看起来没有问题,但是当打开4个线程呢?
防止虚假唤醒
线程也可以唤醒,而不会被通知,中断或超时,即所谓的虚假唤醒。虽然实践中很少发生,但应用程序必须通过测试应该使线程被唤醒的条件来防范,并且如果条件不满足则继续等待。换句话讲,等待应该总是出现在循环中:
将if 修改成while循环判断
lock锁 生产消费者
package JUC;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Copyright © 2021 eSunny Info. Tech Ltd. All rights reserved.
*
* 功能描述:
* @Package: JUC
* @author: 79283
* @date: 2021年1月20日 下午7:13:51
*/
public class ProviderConsumerJUC {
public static void main(String[] args) {
DataJUC data = new DataJUC();
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 DataJUC{
//数字 资源类
private int number = 0;
Lock lock = new ReentrantLock();
//Condition 等待唤醒
Condition newCondition = lock.newCondition();
Condition newCondition2 = lock.newCondition();
// +1
public void increment() throws InterruptedException {
lock.lock();
try {
while (number!=0) {
//等待减少
newCondition.await();
}
number++;
System.out.println(Thread.currentThread().getName() + "票数加 +"+ number);
//通知
newCondition.signalAll();
} catch (Exception e) {
e.getStackTrace();
} finally {
lock.unlock();
}
}
// -1
public void decrement() throws InterruptedException {
lock.lock();
try {
while (number==0) {
//等待增加
newCondition.await();
}
number--;
System.out.println(Thread.currentThread().getName() + "票数减 -"+ number);
//通知
newCondition.signalAll();
} catch (Exception e) {
e.getStackTrace();
} finally {
lock.unlock();
}
}
}