生产者和消费者问题是操作系统的经典问题,在实际工作中也常会用到,主要的难点在于协调生产者和消费者,因为生产者的个数和消费者的个数不确定,而生产者的生成速度与消费者的消费速度也不一样,同时还要实现生产者与消费者的解耦,即生产者并不知道有哪些消费者,而消费者也不需要知道产品是哪个生产的,他们之间只与一个交易平台发生关系。

  这是现实世界普遍存在的问题,比如我们去苹果专卖店买IPhone 6,我们属于消费者,而生产商把产品生产出来放在苹果专卖店,如果全世界只有一个苹果专卖店,当专卖店没有IPhone 6时,我们只有等,而当专卖店屯了很多货,以至于专卖店放不下了时,苹果公司比如要生产商暂停生产。生产者与消费者是通过一个缓存仓库来交易的。

  Java里面有LinkedBlockingQueue、ArrayBlockingQueue可以在并发环境实现阻塞插入和删除,非常适合作为生产者和消费者之间的纽带。

  生产者:

/**
* 生产者
* @author jiqunpeng
*
*/
class Producer implements Runnable { LinkedBlockingQueue<Integer> buffer;
//构造生产者,注册仓库
Producer(LinkedBlockingQueue<Integer> buffer) {
this.buffer = buffer;
}
/**
* 生产一个产品,当仓库已经满时,等待仓库有空地再放入仓库
* @param e
* @throws InterruptedException
*/
public void produce(Integer e) throws InterruptedException {
buffer.put(e);
} @Override
public void run() {
Random random = new Random(7);
try {
while (true) {//一生不息
Integer product = random.nextInt();
System.out.println(this + " \tProduct:\t " + product);
produce(product);
TimeUnit.MILLISECONDS.sleep(random.nextInt(500));//短暂的休息
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

  消费者  

/**
* 消费者
* @author jiqunpeng
*
*/
class Consumer implements Runnable {
LinkedBlockingQueue<Integer> buffer;
//注册仓库
Consumer(LinkedBlockingQueue<Integer> buffer) {
this.buffer = buffer;
}
/**
* 从仓库中的取出产品消费,当仓库里面没有产品时,会一直等下去
* @return
* @throws InterruptedException
*/
public Integer consume() throws InterruptedException {
Integer e = buffer.take();
return e;
} @Override
public void run() {
Random random = new Random(7);
try {
while (true) {//一生都要吃
Integer product = consume();
System.out.println(this + " \tConsume:\t " + product);
TimeUnit.MILLISECONDS.sleep(random.nextInt(2000));//吃了也要睡会
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

  调度运行

public class ProducerConsumer {
public static void main(String[] args) {
// 任务调度器
ExecutorService exec = Executors.newFixedThreadPool(10);
// 仓库
final LinkedBlockingQueue<Integer> buffer = new LinkedBlockingQueue<>(5);
for (int i = 0; i < 2; i++) {
// 创建生产者
Producer p = new Producer(buffer);
// 领到把生产者拉到车间,被迫没日没夜的干活
exec.execute(p);
// 消费者出生了
Consumer c = new Consumer(buffer);
// 消费者一生都在消费
exec.execute(c); }
exec.execute(new Runnable() { @Override
public void run() {
while (true) {
// 定时看一下仓库的空间
System.out.println("buffer :" + buffer.size());
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} });
} }

  模拟结果:

os.Producer@16c163f     Product:     -1156638823
os.Consumer@cf66b Consume: -1156638823
os.Producer@db4fa2 Product: -1156638823
os.Consumer@491c4c Consume: -1156638823
buffer :0
os.Producer@16c163f Product: -1077308326
os.Producer@db4fa2 Product: -1077308326
os.Producer@16c163f Product: 1495978761
os.Producer@db4fa2 Product: 1495978761
os.Consumer@491c4c Consume: -1077308326
os.Consumer@cf66b Consume: -1077308326
os.Producer@16c163f Product: -441191359
os.Producer@db4fa2 Product: -441191359
os.Producer@16c163f Product: -1253369595
os.Producer@db4fa2 Product: -1253369595
os.Producer@16c163f Product: 1511462400
os.Consumer@cf66b Consume: 1495978761
os.Consumer@491c4c Consume: 1495978761
os.Producer@db4fa2 Product: 1511462400
os.Producer@16c163f Product: 518557417

  当然我们也可以自己定义一个线程安全的有界阻塞缓存队列:

public class BoundedBuffer<E> {
private Object[] buffer; final private ReentrantLock lock;
final private Condition notEmpty;
final private Condition notFull; private int count;
private int putIndex;
private int takeIndex; public BoundedBuffer(int size) {
buffer = new Object[size];
lock = new ReentrantLock();
notEmpty = lock.newCondition();
notFull = lock.newCondition();
} public void put(E e) throws InterruptedException {
lock.lock();
try {
while (count == buffer.length)
notFull.await();
buffer[putIndex] = e;
if (++putIndex == buffer.length)// 循环数组
putIndex = 0;
count++;
notEmpty.signal();
} finally {
lock.unlock();
}
} public E take() throws InterruptedException {
lock.lock();
System.out.println("take()");
try {
while (count == 0)
notEmpty.await();
@SuppressWarnings("unchecked")
E item = (E) buffer[takeIndex];
count--;
if (++takeIndex == buffer.length)// 循环数组
takeIndex = 0;
notFull.signal();
return item;
} finally {
lock.unlock();
}
}
}

Java实现生产者和消费者的更多相关文章

  1. Windows下RabbitMQ 的下载、配置、Java实现生产者和消费者例子

    RabbitMQ是一个轻量级的消息代理中间件,支持多种消息通信协议,支持分布式部署,支持运行于多个操作系统,具有灵活.高可用等特性.RabbitMQ支持多种协议,其中最为重要的是高级消息队列协议(AM ...

  2. java实现生产者和消费者问题

    Java实现生产者和消费者问题 欢迎访问我的个人博客,获取更多有用的东西 链接一 链接二 也可以关注我的微信订阅号:CN丶Moti

  3. java之生产者与消费者

    package com.produce; import java.util.LinkedList; import java.util.Queue; /*@author shijin * 生产者与消费者 ...

  4. java线 生产者和消费者

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhbmdydWkxOTg4/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  5. Java实现生产者与消费者模式

    生产者不断向队列中添加数据,消费者不断从队列中获取数据.如果队列满了,则生产者不能添加数据:如果队列为空,则消费者不能获取数据.借助实现了BlockingQueue接口的LinkedBlockingQ ...

  6. Java中生产者与消费者模式

    生产者消费者模式 首先来了解什么是生产者消费者模式.该模式也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题描述了两个共享固定大小缓冲区的线 ...

  7. java之生产者和消费者问题

    package testThread; public class Test3 { public static void main(String[] args) { Clerk c = new Cler ...

  8. 菜鸡的Java笔记 生产者与消费者

    生产者与消费者        代码要求知道做什么用即可        线程间的通讯问题以及 Object 类的支持            基础模型        现在希望实现一种数据的生产和取出的操作 ...

  9. Java 多线程-生产者、消费者

    一.整体代码 ThreadDemo.java public class ThreadDemo { public static void main(String[] args) { Godown god ...

随机推荐

  1. 快速入门:十分钟学会Python

    初试牛刀 假设你希望学习Python这门语言,却苦于找不到一个简短而全面的入门教程.那么本教程将花费十分钟的时间带你走入Python的大门.本文的内容介于教程(Toturial)和速查手册(Cheat ...

  2. mysql metadata lock(二)

    上一篇<mysql metadata lock(一)>介绍了为什么引入MDL,MDL作用以及MDL锁导致阻塞的几种典型场景,文章的最后还留下了一个小小的疑问.本文将更详细的介绍MDL,主要 ...

  3. 十五天精通WCF——终结篇 那些你需要注意的坑

    终于一路走来,到了本系列的最后一篇了,这一篇也没什么好说的,整体知识框架已经在前面的系列文章中讲完了,wcf的配置众多,如果 不加一些指定配置,你可能会遇到一些灾难性的后果,快来一睹为快吧. 一: 第 ...

  4. 可输出sql的PrepareStatement封装

    import java.io.InputStream; import java.io.Reader; import java.net.URL; import java.sql.Connection; ...

  5. SQL Server:数据库角色

    除了上述固定数据库角色之外,还有一种特殊的固定数据库角色,名为public. 数据库的每个合法用户都必须属于public角色,它为数据库中的用户提供了所有默认权限. 一般情况下,public角色允许用 ...

  6. 编写Java应用程序。首先定义一个描述银行账户的Account类,包括成员变 量“账号”和“存款余额”,成员方法有“存款”、“取款”和“余额查询”。其次, 编写一个主类,在主类中测试Account类的功能

    package com.hanqi.test; //银行账号 public class account { private String zhanghao;//账号 //私有余额 private do ...

  7. MySQL 优化之 Linux系统层面调优

    MySQL 一般运行于Linux系统中.对于MySQL的调优一般分为Linux操作系统层面的调优和MySQL层面的调优(当然还有架构层面.业务层面.应用程序层面的调优).操作系统主要是管理和分配硬件资 ...

  8. Oracle not in子连接查询不到值的问题(not in 不能查询null数据)

    前几天在项目中,做数据导入时,发现not in和in 查出来的条数不互补.ATABLE2明明中有些记录在ATABLE3中不存在,但是not in时查不出记录. CREATE TABLE ATABLE2 ...

  9. shutdown

    关机命令 $sudo shutdowm [-hrc] -h定时关机,以分钟为单位的计时,时间或now -h now立即关机 -h +2020分钟后关机 -h 12:0012点关机 -r now立即重启 ...

  10. tar, rar, unrar, zip, unzip

    tar 打包/解包/压缩/解压缩文件,注意打包和压缩不是一回事,打包相当于捆绑,压缩是在捆绑好后再把里面的空隙挤出以生成更小的文件 $tar [-zjxcvf] filename.tar[.gz... ...