多线程之多生产者与多消费者
在上一篇文章里,我们介绍了线程的等待唤醒机制,并用单生产者和单消费者来演示了notify() 和 wait() 等待唤醒相关方法。
这篇文章我们来通过多生产者和多消费者来演示notifyAll()的方法。
我们要实现的效果原理为上图,我们有两个生产者线程,在isProduce = false时,在P1和P2线程中随机一条线程来进行生产商品,生产完毕后,再在C1和C2消费者线程中随机唤醒一条线程来消费商品。
class Resource {
private boolean isProduced = false;
private int count;
public Resource() {
super();
}
public boolean isProduced() {
return isProduced;
}
public void setProduced(boolean isProduced) {
this.isProduced = isProduced;
}
public void produce() {
count++;
System.out.println("生产者线程......" + Thread.currentThread().getName() + ",生产" + count + "商品");
}
public void consume() {
System.out.println("消费者线程..." + Thread.currentThread().getName() + ", 消费" + count + "商品");
}
}
class Producer extends Thread{
private Resource resource;
public Producer(Resource resource) {
super();
this.resource = resource;
}
@Override
public void run() {
synchronized (resource) {
while(true) {
if(resource.isProduced()) {
try {
resource.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
resource.produce();
resource.setProduced(true);
resource.notifyAll();
}
}
}
}
}
class Consumer extends Thread{
private Resource resource;
public Consumer(Resource resource) {
super();
this.resource = resource;
}
@Override
public void run() {
while(true) {
synchronized (resource) {
if(!resource.isProduced()) {
try {
resource.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
resource.consume();
resource.setProduced(false);
resource.notifyAll();
}
}
}
}
}
package com.evan.multi_producer_consumer;
public class Demo {
public static void main(String[] args) {
Resource resource = new Resource();
Producer p1 = new Producer(resource);
Producer p2 = new Producer(resource);
Consumer c1 = new Consumer(resource);
Consumer c2 = new Consumer(resource);
p1.start();
p2.start();
c1.start();
c2.start();
}
}
运行效果如上图。
我们发现Thread - 0 和 Thread - 1为生产者线程,Thread - 2 和 Thread - 3 为消费者线程。
在Producer.class的run方法中,我们判断如果isProduced == true,那么我们自己就睡眠,如果isProduced == false,那么我们就生产一个商品,生产完之后,我们睡眠,睡眠之前调用notifyAll()。
在Consumer.class的run方法中,我们判断如果isProduced == false, 那么我们自己就睡眠,如果isProduced == true,那么我们就消费一个商品,消费完之后,我们睡眠,睡眠之前调用notifyAll()。
这里和单生产者单消费者文章里唯一不同的就是将notify()方法替换为了notifyAll()方法。
我们在使用Object.wait() 时,是将当前线程睡眠在了这个对象背后的池子里,而这个池子里可以睡眠N多条线程。
当我们在调用notify()时,他的工作原理是在池子里随机唤醒一条线程。
而我们现在有4条线程,p1 p2 c1 c2,假设p1生产完毕,需要唤醒p2 c1 c2中的消费者线程,那么因为notify是随机的,我们无法保证唤醒的是c1 和 c2中的一条,所以我们需要使用notifyAll() 线程,来将这3条线程都唤醒,那么p2就算唤醒了,当判断到标记isProduced = true时,也会自动睡眠,从而保证了消费者阵营中,有一条线程去消费该商品。