1、生产/消费者模型

生产/消费者问题是个非常典型的多线程问题,涉及到的对象包括“生产者”、“消费者”、“仓库”和“产品”。他们之间的关系如下:

(01) 生产者仅仅在仓储未满时候生产,仓满则停止生产。

(02) 消费者仅仅在仓储有产品时候才能消费,仓空则等待。

(03) 当消费者发现仓储没产品可消费时候会通知生产者生产。

(04) 生产者在生产出可消费产品时候,应该通知等待的消费者去消费。

2、生产者消费者实现(synchronized )

// Demo1.java
// 仓库
class Depot {
private int capacity; // 仓库的容量
private int size; // 仓库的实际数量 public Depot(int capacity) {
this.capacity = capacity;
this.size = 0;
} public synchronized void produce(int val) {
try {
// left 表示“想要生产的数量”(有可能生产量太多,需多此生产)
int left = val;
while (left > 0) {
// 库存已满时,等待“消费者”消费产品。
while (size >= capacity)
wait();
// 获取“实际生产的数量”(即库存中新增的数量)
// 如果“库存”+“想要生产的数量”>“总的容量”,则“实际增量”=“总的容量”-“当前容量”。(此时填满仓库)
// 否则“实际增量”=“想要生产的数量”
int inc = (size+left)>capacity ? (capacity-size) : left;
size += inc;
left -= inc;
System.out.printf("%s produce(%3d) --> left=%3d, inc=%3d, size=%3d\n",
Thread.currentThread().getName(), val, left, inc, size);
// 通知“消费者”可以消费了。
notifyAll();
}
} catch (InterruptedException e) {
}
} public synchronized void consume(int val) {
try {
// left 表示“客户要消费数量”(有可能消费量太大,库存不够,需多此消费)
int left = val;
while (left > 0) {
// 库存为0时,等待“生产者”生产产品。
while (size <= 0)
wait();
// 获取“实际消费的数量”(即库存中实际减少的数量)
// 如果“库存”<“客户要消费的数量”,则“实际消费量”=“库存”;
// 否则,“实际消费量”=“客户要消费的数量”。
int dec = (size<left) ? size : left;
size -= dec;
left -= dec;
System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d\n",
Thread.currentThread().getName(), val, left, dec, size);
notifyAll();
}
} catch (InterruptedException e) {
}
} public String toString() {
return "capacity:"+capacity+", actual size:"+size;
}
} // 生产者
class Producer {
private Depot depot; public Producer(Depot depot) {
this.depot = depot;
} // 消费产品:新建一个线程向仓库中生产产品。
public void produce(final int val) {
new Thread() {
public void run() {
depot.produce(val);
}
}.start();
}
} // 消费者
class Customer {
private Depot depot; public Customer(Depot depot) {
this.depot = depot;
} // 消费产品:新建一个线程从仓库中消费产品。
public void consume(final int val) {
new Thread() {
public void run() {
depot.consume(val);
}
}.start();
}
} public class Demo1 {
public static void main(String[] args) {
Depot mDepot = new Depot(100);
Producer mPro = new Producer(mDepot);
Customer mCus = new Customer(mDepot); mPro.produce(60);
mPro.produce(120);
mCus.consume(90);
mCus.consume(150);
mPro.produce(110);
}
}

运行结果

Thread-0 produce( 60) --> left=  0, inc= 60, size= 60
Thread-4 produce(110) --> left= 70, inc= 40, size=100
Thread-2 consume( 90) <-- left= 0, dec= 90, size= 10
Thread-3 consume(150) <-- left=140, dec= 10, size= 0
Thread-1 produce(120) --> left= 20, inc=100, size=100
Thread-3 consume(150) <-- left= 40, dec=100, size= 0
Thread-4 produce(110) --> left= 0, inc= 70, size= 70
Thread-3 consume(150) <-- left= 0, dec= 40, size= 30
Thread-1 produce(120) --> left= 0, inc= 20, size= 50

3、生产者消费者实现(Lock锁)

package Thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; class Depot{
private int capacity; //仓库容量
private int size; //仓库当前产品数量
private Lock lock; //锁
private Condition productCondition; //生产条件
private Condition consumerCondition; //消费条件 public Depot(int capacity) {
this.capacity=capacity;
this.size=0;
this.lock = new ReentrantLock();
this.productCondition = this.lock.newCondition();
this.consumerCondition = this.lock.newCondition();
} //生产商品
public void produce(int val) {
lock.lock();
try {
int left=val; //left表示需要生产的数量
while (left > 0) {
//当库存已满时,则生产者开始等待消费者消费
while (size == capacity) {
productCondition.await();
}
int pro= left > (capacity-size) ? (capacity-size) : left; //如果生产的数量大于仓库容量,则只生产仓库容量这么多
size += pro;
left -= pro;
System.out.printf("%s produce(%3d) --> left=%3d, inc=%3d, size=%3d\n",
Thread.currentThread().getName(), val, left, pro, size);
consumerCondition.signal(); //消费者消费时,发现当仓库产品为零时,此时消费者等待,调用生产者生产,那么生产者生产完成后则需要释放消费者
} }catch (Exception e){ }finally {
lock.unlock();
}
} //消费商品
public void consume(int val) {
lock.lock();
try {
int left=val; //left表示需要消费的数量
while (left > 0) {
while (size == 0) { //当前商品数量为零时,消费者需要等待
consumerCondition.await();
}
int cus=left > size? size : left;
size -= cus;
left -= cus;
System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d\n",
Thread.currentThread().getName(), val, left, cus, size);
productCondition.signal(); //消费者消费完成后,需要释放生产者
}
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
} }
} //生产者
class Producer{ private Depot depot; public Producer(Depot depot) {
this.depot = depot;
} public void produce(int val){
new Thread(){
@Override
public void run() {
depot.produce(val);
}
}.start();
}
} //消费者
class Customer{
private Depot depot; public Customer(Depot depot) {
this.depot = depot;
} public void consume(int val) {
new Thread(){
@Override
public void run() {
depot.consume(val);
}
}.start();
} } public class LockTest {
public static void main(String[] args) {
Depot mDepot = new Depot(100);
Producer mPro = new Producer(mDepot);
Customer mCus = new Customer(mDepot); mPro.produce(60);
mPro.produce(120);
mCus.consume(90);
mCus.consume(150);
mPro.produce(110);
}
}

运行结果

Thread-0 produce( 60) --> left=  0, inc= 60, size= 60
Thread-1 produce(120) --> left= 80, inc= 40, size=100
Thread-2 consume( 90) <-- left= 0, dec= 90, size= 10
Thread-3 consume(150) <-- left=140, dec= 10, size= 0
Thread-4 produce(110) --> left= 10, inc=100, size=100
Thread-3 consume(150) <-- left= 40, dec=100, size= 0
Thread-4 produce(110) --> left= 0, inc= 10, size= 10
Thread-3 consume(150) <-- left= 30, dec= 10, size= 0
Thread-1 produce(120) --> left= 0, inc= 80, size= 80
Thread-3 consume(150) <-- left= 0, dec= 30, size= 50

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

  1. 第23章 java线程通信——生产者/消费者模型案例

    第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...

  2. java多线程解决生产者消费者问题

    import java.util.ArrayList; import java.util.List; /** * Created by ccc on 16-4-27. */ public class ...

  3. java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-【费元星Q9715234】

    java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-[费元星Q9715234] 说明如下,不懂的问题直接我[费元星Q9715234] 1.反射的意义在于不将xml tag ...

  4. Java设计模式之生产者消费者模式

    Java设计模式之生产者消费者模式 博客分类: 设计模式 设计模式Java多线程编程thread 转载 对于多线程程序来说,不管任何编程语言,生产者和消费者模型都是最经典的.就像学习每一门编程语言一 ...

  5. java多线程模拟生产者消费者问题,公司面试常常问的题。。。

    package com.cn.test3; //java多线程模拟生产者消费者问题 //ProducerConsumer是主类,Producer生产者,Consumer消费者,Product产品 // ...

  6. JAVA多线程之生产者 消费者模式 妈妈做面包案例

    创建四个类 1.面包类 锅里只可以放10个面包 ---装面包的容器2.厨房 kitchen 生产面包 和消费面包  最多生产100个面包3.生产者4消费者5.测试类 多线程经典案例 import ja ...

  7. Java里的生产者-消费者模型(Producer and Consumer Pattern in Java)

    生产者-消费者模型是多线程问题里面的经典问题,也是面试的常见问题.有如下几个常见的实现方法: 1. wait()/notify() 2. lock & condition 3. Blockin ...

  8. Java并发之:生产者消费者问题

    生产者消费者问题是Java并发中的常见问题之一,在实现时,一般可以考虑使用juc包下的BlockingQueue接口,至于具体使用哪个类,则就需要根据具体的使用场景具体分析了.本文主要实现一个生产者消 ...

  9. Java多线程同步——生产者消费者问题

    这是马士兵老师的Java视频教程里的一个生产者消费者问题的模型 public class ProduceConsumer{ public static void main(String[] args) ...

  10. java模拟实现生产者---消费者问题

    本文章为小编原创,请尊重文章的原创性,转载请注意写明转载来源:http://blog.csdn.net/u012116457 已知技术參数: 生产者消费者问题,描写叙述一组生产者向一组消费者提供产品/ ...

随机推荐

  1. Redis对象——有序集合(ZSet)

    有序集合类型 (Sorted Set或ZSet) 相比于集合类型多了一个排序属性 score(分值),对于有序集合 ZSet 来说,每个存储元素相当于有两个值组成的,一个是有序结合的元素值,一个是排序 ...

  2. Linux C++ 网络编程学习系列(1)——端口复用实现

    Linux C++ 网络编程学习系列(1)--端口复用实现 源码地址:https://github.com/whuwzp/linuxc/tree/master/portreuse 源码说明: serv ...

  3. CVE-2020-0796 永恒之蓝?

    0X00漏洞简介 Microsoft Windows和Microsoft Windows Server都是美国微软(Microsoft)公司的产品,Microsoft Windows是一套个人设备使用 ...

  4. redis集群搭建-3.0/4.0版本

    1.  Redis的安装 1.1. Redis的安装 Redis是c语言开发的. 安装redis需要c语言的编译环境.如果没有gcc需要在线安装.yum install gcc-c++ 安装步骤: 第 ...

  5. ThreeJs 导入外部三维模型,并实现鼠标滚动放大缩小旋转效果

    let i = ; function init() { // create a scene, that will hold all our elements such as objects, came ...

  6. python实现双向链表的操作

    双向链表 双向链表又叫做双链表,每个节点有两个指针域和一个数据域.prev指针域指向前一个节点,next指针域指向下一个节点.注意,第一个节点的prev指针域指向空值,最后一个节点的next域也是指向 ...

  7. Docker常用命令--ps/attach/run

    ps查看container 若查看正在运行的container docker ps 查看所有的container docker ps -a run启动容器 第一次启动container docker ...

  8. 计算机系统基础学习笔记(1)-基本GCC,objdump,GBD命令的使用

    基本GCC命令的使用 GCC是一套由GNU项目开发的编程语言编译器,可处理C语言. C++.Fortran.Pascal.Objective-C.Java等等.GCC通常是 跨平台软件的编译器首选.g ...

  9. radio取值

    假设代码如下: 1) <input type="radio"   name="radio"   id="radio1"  checke ...

  10. java IO流 之 字节流与字符流

    其实学习了file文件基础类,后面的字节流和字符流都特别简单了,首先需要知道字节流和字符流的区别 字节流: 用来传送图片.各种文件.大文件.文本都是通过字节流进行传输的. 字符流: 只能读取文本信息 ...