首先写一个生产者消费者案例
public class ProductAndConsumer03 {
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 num = 0;
// +1操作,利用关键字加锁
public synchronized void increment() throws InterruptedException {
//首先查看仓库中的资源(num),如果资源不为0,就利用 wait 方法等待消费,释放锁
if(num!=0){
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName()+"=>"+num);
//通知其他线程 +1 执行完毕
this.notifyAll();
}
//-1操作
public synchronized void decrement() throws InterruptedException {
//首先查看仓库中的资源(num),如果资源为0,就利用 wait 方法等待生产,释放锁
if(num==0){
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName()+"=>"+num);
//通知其他线程 -1 执行完毕
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
模仿上面的案例在增加一个生产者和消费者
package com.cn.Callable;
//虚假唤醒
public class ProductAndConsumer03 {
public static void main(String[] args) {
Data data = new Data();
//创建一个生产者 A
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
//创建一个消费者 B
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
//创建一个生产者 C
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
//创建一个消费者 D
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 {
//首先查看仓库中的资源(num),如果资源不为0,就利用 wait 方法等待消费,释放锁
if(num!=0){
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName()+"=>"+num);
//通知其他线程 +1 执行完毕
this.notifyAll();
}
//-1操作
public synchronized void decrement() throws InterruptedException {
//首先查看仓库中的资源(num),如果资源为0,就利用 wait 方法等待生产,释放锁
if(num==0){
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName()+"=>"+num);
//通知其他线程 -1 执行完毕
this.notifyAll();
}
}
结果 我们发现出现了2这个不正确的结果(每次结果都可能不同)(if造成的,if只会判断一次)
A=>1 B=>0 A=>1 B=>0 A=>1 B=>0 A=>1 B=>0A=>1 B=>0 A=>1 B=>0 A=>1 B=>0 A=>1 B=>0 A=>1 B=>0
C=>1 B=>0 A=>1 C=>2 D=>1 C=>2 D=>1 D=>0 C=>1 D=>0 C=>1 D=>0 C=>1 D=>0 C=>1 D=>0 C=>1 D=>0 C=>1 D=>0 C=>1 D=>0
我们来看一下jdk帮助文档
使用while替代if解决虚假唤醒问题
package com.cn.Callable;
//虚假唤醒
public class ProductAndConsumer03 {
public static void main(String[] args) {
Data data = new Data();
//创建一个生产者 A
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
//创建一个消费者 B
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
//创建一个生产者 C
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
//创建一个消费者 D
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 {
//首先查看仓库中的资源(num),如果资源不为0,就利用 wait 方法等待消费,释放锁
while(num!=0){
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName()+"=>"+num);
//通知其他线程 +1 执行完毕
this.notifyAll();
}
//-1操作
public synchronized void decrement() throws InterruptedException {
//首先查看仓库中的资源(num),如果资源为0,就利用 wait 方法等待生产,释放锁
while(num==0){
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName()+"=>"+num);
//通知其他线程 -1 执行完毕
this.notifyAll();
}
}
结果正确
A=>1 B=>0 C=>1 B=>0 A=>1 B=>0 C=>1 B=>0 A=>1 B=>0 C=>1 B=>0 A=>1 B=>0 C=>1 B=>0 A=>1 B=>0
C=>1 B=>0 A=>1 D=>0 C=>1 D=>0 A=>1 D=>0 C=>1 D=>0 A=>1 D=>0 C=>1 D=>0 A=>1 D=>0 C=>1 D=>0 A=>1 D=>0 C=>1 D=>0
参考教程:狂神学Java
参考文章:https://blog.csdn.net/qq_36188127/article/details/110501841