生产者消费者模型
1.简介:
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的
/**
* @Author Yan
* @Create 2019/9/20 17:26 by IntelliJ IDEA
* @Description
*/
class Goods{
//商品名称
private String goodsName;
//商品库存
private int count;
@Override
public String toString() {
return "Goods{" +
"goodsName='" + goodsName + '\'' +
", count=" + count +
'}';
}
//生产方法
public synchronized void set(String goodsName){
this.goodsName = goodsName;
this.count = count+1;
System.out.println(toString());
}
//消费方法
public synchronized void get(){
this.count = this.count -1;
System.out.println(toString());
}
}
/*
* 生产者
* */
class Producer implements Runnable{
private Goods goods;
public Producer(Goods goods) {
super();
this.goods = goods;
}
@Override
public void run() {
this.goods.set("奔驰");
}
}
/*
* 消费者
* */
class Consumer implements Runnable{
private Goods goods;
public Consumer(Goods goods) {
super();
this.goods = goods;
}
@Override
public void run() {
this.goods.get();
}
}
//测试类
public class FactoryDesignModel {
public static void main(String[] args) throws InterruptedException {
Goods goods = new Goods();
Thread produseThread = new Thread(new Producer(goods));//生产者线程
Thread consumerThread = new Thread(new Consumer(goods));//消费者线程
//启动生产者线程
produseThread.start();
Thread.sleep(1000);
//启动消费者线程
consumerThread.start();
}
}
运行结果:
Goods{goodsName=‘奔驰’, count=1}
Goods{goodsName=‘奔驰’, count=0}
但是将生产者线程开启和消费者线程开启的代码换个位置在再测试下。此时问题产生了,生
产者还没生产商品消费者就消费了导致数量不正确。此时就需要我们的wait()和notify()方法帮忙。
class Goods{
//商品名称
private String goodsName;
//商品库存
private int count;
//商品生产
public synchronized void set(String goodsName) throws InterruptedException {
if (this.count > 0){
System.out.println("还有库存,等待消费..........");
wait();
}
this.goodsName = goodsName;
this.count = count+1;
Thread.sleep(1000);
System.out.println("生产:"+toString());
//生产完商品通知消费者可一消费了
notify();
}
//商品消费
public synchronized void get() throws InterruptedException {
//此时还没有商品,等待生产者生产商品
if (this.count == 0){
System.out.println("此时没有商品,等待生产者生产");
wait();
}
//每次消费一个商品
this.count = this.count -1;
Thread.sleep(1000);
System.out.println("消费"+toString());
//消费完告诉生产者继续生产
notify();
}
@Override
public String toString() {
return "Goods{" +
"goodsName='" + goodsName + '\'' +
", count=" + count +
'}';
}
}
/*
* 生产者
* */
class Produser implements Runnable{
private Goods goods;
public Produser(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
try {
this.goods.set("宝马");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
* 消费者
* */
class Consumer implements Runnable{
private Goods goods;
public Consumer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
try {
this.goods.get();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//测试类
public class FactoryDesignModel {
public static void main(String[] args) {
Goods goods = new Goods();
Thread produsThread = new Thread(new Produser(goods));//生产者线程
Thread consumerThread = new Thread(new Consumer(goods));//消费者线程
//启动消费者线程
consumerThread.start();
//启动生产者线程
produsThread.start();
}
}
运行结果:
此时没有商品,等待生产者生产
生产:Goods{goodsName=‘宝马’, count=1}
消费Goods{goodsName=‘宝马’, count=0}
多生产以及多消费
以上只有一个生产者生产一次商品和一个消费者只消费一次就结束了,现在能否改变一下,多个生产者和多个消费者呢?
分析一下,首先notify方法目前是只能唤醒一个线程,如果有多个生产者线程和多个消费者线程的话,这个notify方法唤醒的线程如果是消费者的话应该没有问题,但是如果是唤醒的也是生产者的线程那么程序就会变成假死状态了,这个时候显然这个notify方法不行,我们上一节讲过了有一个notifyAll()唤醒当前对象的所有线程。这个时候就可以使用该方法了,好了我们开始改造。
class Goods{
//商品名称
private String goodsName;
//商品库存
private int count;
//商品生产
public synchronized void set(String goodsName) throws InterruptedException {
//此时还没有商品被消费,等待消费者消费
while (this.count > 0){
wait();
}
this.goodsName = goodsName;
this.count = count+1;
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
System.out.println("生产"+toString());
System.out.println("====================================");
//生产完商品通知消费者消费
notifyAll();
}
//商品消费
public synchronized void get() throws InterruptedException {
//此时还没有商品,等待生产者生产商品
while (this.count == 0){
wait();
}
//每次消费一个商品
this.count = this.count -1;
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
System.out.println("消费"+toString());
System.out.println("========================================");
//消费完告诉生产者继续生产
notifyAll();
}
@Override
public String toString() {
return "Goods{" +
"goodsName='" + goodsName + '\'' +
", count=" + count +
'}';
}
}
/*
* 生产者
* */
class Produser implements Runnable{
private Goods goods;
public Produser(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while (true) {
try {
this.goods.set("奥迪");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/*
* 消费者
* */
class Consumer implements Runnable{
private Goods goods;
public Consumer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while (true) {
try {
this.goods.get();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//测试类
public class FactoryDesignModel {
public static void main(String[] args) {
Goods goods = new Goods();
List<Thread> threadList = new ArrayList<>();
//10个生产者线程
for (int i = 0; i < 10; i++) {
Thread produseThread = new Thread(new Produser(goods));
produseThread.setName("生产者线程"+i);
threadList.add(produseThread);
}
//6个消费者线程
for (int i = 0; i < 6; i++) {
Thread consumerThread = new Thread(new Consumer(goods));
consumerThread.setName("消费者线程"+i);
threadList.add(consumerThread);
}
for (Thread thread:threadList) {
thread.start();
}
}
}