生产者消费者模型三种实现实例

生产者消费者模型,最少两个线程,一个生产资源,一个消费资源。 没有资源时,消费者线程需要挂起,等待生产者生产好了再去消费。 生产者生产过多,仓库放不下时,生产者线程需要挂起,等待消费者消费后,仓库腾出地方了再去生产。


就像包子店卖包子。生意火爆时,包子刚出笼就被抢光了,那后来的人在想买就要等待,等待老板再蒸包子,蒸好了再买。 生意不好的时候,蒸好的包子没人买,笼屉里面都是包子。老板想再蒸点包子也没地方放,只能等后来顾客来卖包子了,腾出来笼屉了,才能再蒸。


其中关键点在于,在相应的时间点挂起线程,在相应的时间点唤醒线程。

下面是三种方式的实现实例。

1、object的wait和notify实现生产者消费者

package designmode.productconsumermode.pcwithwaitandnotify;

// object的wait和notify实现生产者消费者
public class ProducerConsumerWithWaitNofity {
 public static void main(String[] args) {
 Resource resource = new Resource();
 //生产者线程
 ProducerThread p1 = new ProducerThread(resource);
 ProducerThread p2 = new ProducerThread(resource);
 ProducerThread p3 = new ProducerThread(resource);
 //消费者线程
 ConsumerThread c1 = new ConsumerThread(resource);
 //ConsumerThread c2 = new ConsumerThread(resource);
 //ConsumerThread c3 = new ConsumerThread(resource);

 p1.start();
 p2.start();
 p3.start();
 c1.start();
 //c2.start();
 //c3.start();
 }
}

/**
 * 公共资源类
 */
class Resource {//重要
 //当前资源数量
 private int num = 0;
 //资源池中允许存放的资源数目
 private int size = 1;

 /**
 * 从资源池中取走资源
 */
 public synchronized void remove() {
 if (num == size) {
 num--;
 System.out.println("消费者" + Thread.currentThread().getName() +
 "消耗一件资源," + "当前线程池有" + num + "个");
 notifyAll();//通知生产者生产资源
 } else {
 try {
 //如果没有资源,则消费者进入等待状态
 wait();
 System.out.println("消费者" + Thread.currentThread().getName() + "线程进入等待状态");
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
 }

 /**
 * 向资源池中添加资源
 */
 public synchronized void add() {
 if (num == 0) {
 num++;
 System.out.println(Thread.currentThread().getName() + "生产一件资源,当前资源池有"
 + num + "个");
 notifyAll(); // 通知消费者消费资源
 } else {
 //如果当前资源池中有10件资源
 try {
 wait();//生产者进入等待状态,并释放锁
 System.out.println(Thread.currentThread().getName() + "线程进入等待");
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
 }
}

/**
 * 消费者线程
 */
class ConsumerThread extends Thread {
 private Resource resource;

 public ConsumerThread(Resource resource) {
 this.resource = resource;
 }

 @Override
 public void run() {
 // 不断去消耗资源
 while (true) {
 try {
 Thread.sleep(1000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 resource.remove();
 }
 }
}

/**
 * 生产者线程
 */
class ProducerThread extends Thread {
 private Resource resource;

 public ProducerThread(Resource resource) {
 this.resource = resource;
 }

 @Override
 public void run() {
 //不断地生产资源
 while (true) {
 try {
 Thread.sleep(1000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 resource.add();
 }
 }
}

2、使用Condition、lock实现生产者消费者

package designmode.productconsumermode.pcwithlockcondition;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

// 使用Condition、lock实现生产者消费者
public class TestPCwithConditionLock {
 public static void main(String[] args) {
 Lock lock = new ReentrantLock();
 Condition proCd = lock.newCondition();
 Condition conCd = lock.newCondition();
 Resource resource = new Resource(lock, proCd, conCd);
 ProThread pro = new ProThread(resource);
 Thread con = new Thread(new ConThread(resource));
 Thread con1 = new Thread(new ConThread(resource));
 pro.start();
 con.start();
 con1.start();
 }
}

class ProThread extends Thread {
 private Resource resource;

 public ProThread(Resource resource) {
 this.resource = resource;
 }

 @Override
 public void run() {
 while (true) {
 try {
 sleep((long) (1000 * Math.random()));
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 resource.product();
 }
 }
}

class ConThread implements Runnable {
 private Resource resource;

 public ConThread(Resource resource) {
 this.resource = resource;
 }

 @Override
 public void run() {
 while (true) {
 try {
 Thread.sleep((long) (1000 * Math.random()));
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 resource.consumer();
 }
 }
}

class Resource {
 private int max = 10; // 资源池容量
 private int count = 0; // 当前资源数量
 private Lock lock;
 private Condition proCd;
 private Condition conCd;

 public Resource(Lock lock, Condition proCd, Condition conCd) {
 this.lock = lock;
 this.proCd = proCd;
 this.conCd = conCd;
 }

 public void product() {
 lock.lock();
 try {
 if (count < max) {
 count++;
 System.out.println("线程[" + Thread.currentThread().getName() + "]:正在生产,当前资源池容量为:" + count);
 conCd.signalAll();
 } else {
 proCd.await();
 System.out.println("资源池容量已满,停止生产,生产线程[" + Thread.currentThread().getName() + "}挂起");
 }
 } catch (InterruptedException e) {
 e.printStackTrace();
 } finally {
 lock.unlock();
 }
 }

 public void consumer() {
 lock.lock();
 try {
 if (count > 0) {
 count--;
 System.out.println("线程[" + Thread.currentThread().getName() + "]:正在消费,当前资源池容量为:" + count);
 proCd.signalAll();
 } else {
 conCd.await();
 System.out.println("资源池容量为0,无法消费,消费线程[" + Thread.currentThread().getName() + "}挂起");
 }
 } catch (InterruptedException e) {
 e.printStackTrace();
 } finally {
 lock.unlock();
 }
 }
}

3、阻塞队列BlockingQueue实现生产者消费者

package designmode.productconsumermode.pcwithblockingqueue;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

//使用阻塞队列BlockingQueue实现生产者消费者
public class BlockingQueueConsumerProducer {
 public static void main(String[] args) {
 Resource3 resource = new Resource3();
 //生产者线程
 ProducerThread3 p = new ProducerThread3(resource);
 //多个消费者
 ConsumerThread3 c1 = new ConsumerThread3(resource);
 ConsumerThread3 c2 = new ConsumerThread3(resource);

 p.start();
 c1.start();
 c2.start();
 }
}

/**
 * 消费者线程
 */
class ConsumerThread3 extends Thread {
 private Resource3 resource3;

 public ConsumerThread3(Resource3 resource) {
 this.resource3 = resource;
 }

 public void run() {
 while (true) {
 try {
 Thread.sleep((long) (1000 * Math.random()));
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 resource3.remove();
 }
 }
}

/**
 * 生产者线程
 */
class ProducerThread3 extends Thread {
 private Resource3 resource3;

 public ProducerThread3(Resource3 resource) {
 this.resource3 = resource;
 }

 public void run() {
 while (true) {
 try {
 Thread.sleep((long) (1000 * Math.random()));
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 resource3.add();
 }
 }
}

class Resource3 {
 private BlockingQueue resourceQueue = new LinkedBlockingQueue(10);

 /**
 * 向资源池中添加资源
 */
 public void add() {
 try {
 resourceQueue.put(1);
 System.out.println("生产者" + Thread.currentThread().getName()
 + "生产一件资源," + "当前资源池有" + resourceQueue.size() +
 "个资源");
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }

 /**
 * 向资源池中移除资源
 */
 public void remove() {
 try {
 resourceQueue.take();
 System.out.println("消费者" + Thread.currentThread().getName() +
 "消耗一件资源," + "当前资源池有" + resourceQueue.size()
 + "个资源");
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
}

运行下实例,再仿着写一下就理解了。

关于wait、notify线程基础知识不太熟悉的可以看这个:https://www.jianshu.com/p/2b56a169866c

《生产者与消费者问题算法实现》 设计思想 因为有多个缓冲区,所以生产者线程没有必要在生成新的数据之前等待最后一个数据被消费者线程处理完毕。同样,消费者线程并不一定每次只能处理一个数据。在多缓冲区机制下,线程之间不必互相等待形成死锁,因而提高了效率。   多个缓冲区就好像使用一条传送带替代托架,传送带上一次可以放多个产品。生产者在缓冲区尾加入数据,而消费者则在缓冲区头读取数据。当缓冲区满的时候,缓冲区就上锁并等待消费者线程读取数据;每一个生产或消费动作使得传送带向前移动一个单位,因而,消费者线程读取数据的顺序和数据产生顺序是相同的。 可以引入一个count计数器来表示已经被使用的缓冲区数量。用hNotEmptyEvent 和hNotFullEvent 来同步生产者和消费者线程。每当生产者线程发现缓冲区满( count=BufferSize ),它就等待hNotEmptyEvent 事件。同样,当消费者线程发现缓冲区空,它就开始等待hNotEmptyEvent。生产者线程写入一个新的数据之后,就立刻发出hNotEmptyEvent 来唤醒正在等待的消费者线程;消费者线程在读取一个数据之后,就发出hNotFullEvent 来唤醒正在等待的生产者线程。 程序的设计思想大致为:设置一while循环,pi生产者访问临界区,得到权限访问缓冲区,如果缓冲区满的,则等待,直到缓冲区非满;访问互斥锁,当得到互斥锁且缓冲区非满时,跳出while循环,开始产生新数据,并把数据存放于Buffer缓冲区中,当数据存放结束则结束临界区;接着唤醒消费者线程;ci消费者访问临界区,得到权限访问缓冲区,如果缓冲区为空,没有可以处理的数据,则释放互斥锁且等待,直到缓冲区非空;当等到缓冲区非空时,跳出while循环;消费者获得数据,并根据所获得的数据按类别消费(当消费者获得的数据为大写字母时,则把大写字母转换成小写字母,并显示;当消费者获得的数据为小写字母时,则把小写字母转换成大写字母,并显示;当消费者获得的数据为字符0、1、2、……8、9时,把这些字符直接显示到屏幕;当消费者获得的数据为符号(+、-、*、\……)时,把这些符号打印成7行7列的菱形);处理完数据后,结束临界区;接着唤醒生产者线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值