Java多线程(九):生产者消费者模型
生产者消费者模型
生产者:生产任务的个体;
消费者:消费任务的个体;
缓冲区:是生产者和消费者之间的媒介,对生产者和消费者解耦。
当
缓冲区元素为满,生产者无法生产,消费者继续消费;
缓冲区元素为空,消费者无法消费,生产者继续生产;
wait()/notify()生产者消费者模型
制作一个简单的缓冲区ValueObject,value为空表示缓冲区为空,value不为空表示缓冲区满
public class ValueObject {
public static String value = "";
}
生产者,缓冲区满则wait(),不再生产,等待消费者notify(),缓冲区为空则开始生产
public class Producer {
private Object lock;
public Producer(Object lock)
{
this.lock = lock;
}
public void setValue()
{
try
{
synchronized (lock)
{
if (!ValueObject.value.equals(""))
lock.wait();
String value = System.currentTimeMillis() + "_" + System.nanoTime();
System.out.println("Set的值是:" + value);
ValueObject.value = value;
lock.notify();
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
消费者,缓冲区为空则wait(),等待生产者notify(),缓冲区为满,消费者开始消费
public class Customer {
private Object lock;
public Customer(Object lock)
{
this.lock = lock;
}
public void getValue()
{
try
{
synchronized (lock)
{
if (ValueObject.value.equals(""))
lock.wait();
System.out.println("Get的值是:" + ValueObject.value);
ValueObject.value = "";
lock.notify();
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
main方法,启动一个生产者和一个消费者
public class Main {
public static void main(String[] args)
{
Object lock = new Object();
final Producer producer = new Producer(lock);
final Customer customer = new Customer(lock);
Runnable producerRunnable = new Runnable()
{
public void run()
{
while (true)
{
producer.setValue();
}
}
};
Runnable customerRunnable = new Runnable()
{
public void run()
{
while (true)
{
customer.getValue();
}
}
};
Thread producerThread = new Thread(producerRunnable);
Thread CustomerThread = new Thread(customerRunnable);
producerThread.start();
CustomerThread.start();
}
}
运行结果如下
Set的值是:1564733938518_27520480474279
Get的值是:1564733938518_27520480474279
Set的值是:1564733938518_27520480498378
Get的值是:1564733938518_27520480498378
Set的值是:1564733938518_27520480540254
Get的值是:1564733938518_27520480540254
······
生产者和消费者交替运行,生产者生产一个字符串,缓冲区为满,消费者消费一个字符串,缓冲区为空,循环往复,满足生产者/消费者模型。
await()/signal()生产者/消费者模型
缓冲区
public class ValueObject {
public static String value = "";
}
ThreadDomain48继承ReentrantLock,set方法生产,get方法消费
public class ThreadDomain48 extends ReentrantLock
{
private Condition condition = newCondition();
public void set()
{
try
{
lock();
while (!"".equals(ValueObject.value))
condition.await();
ValueObject.value = "123";
System.out.println(Thread.currentThread().getName() + "生产了value, value的当前值是" + ValueObject.value);
condition.signal();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
unlock();
}
}
public void get()
{
try
{
lock();
while ("".equals(ValueObject.value))
condition.await();
ValueObject.value = "";
System.out.println(Thread.currentThread().getName() + "消费了value, value的当前值是" + ValueObject.value);
condition.signal();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
unlock();
}
}
}
MyThread41启动两个生产线程和一个消费线程
public class MyThread41 {
public static void main(String[] args)
{
final ThreadDomain48 td = new ThreadDomain48();
Runnable producerRunnable = new Runnable()
{
public void run()
{
for (int i = 0; i < Integer.MAX_VALUE; i++)
td.set();
}
};
Runnable customerRunnable = new Runnable()
{
public void run()
{
for (int i = 0; i < Integer.MAX_VALUE; i++)
td.get();
}
};
Thread ProducerThread1 = new Thread(producerRunnable);
ProducerThread1.setName("Producer1");
Thread ProducerThread2 = new Thread(producerRunnable);
ProducerThread2.setName("Producer2");
Thread ConsumerThread = new Thread(customerRunnable);
ConsumerThread.setName("Consumer");
ProducerThread1.start();
ProducerThread2.start();
ConsumerThread.start();
}
}
输出结果如下
Producer1生产了value, value的当前值是123
Consumer消费了value, value的当前值是
Producer1生产了value, value的当前值是123
为什么Producer2无法生产,消费者无法消费呢?是因为此时缓冲区为满,Producer1的notify()应该唤醒Consumer却唤醒了Producer2,导致Producer2因为缓冲区为满和Consumer没有被唤醒而处于waiting状态,此时三个线程均在等待,出现了假死。
解决方案有两种:
1.让生产者唤醒所有线程,在set方法中使用condition.signalAll();
2.使用两个Condition,生产者Condition和消费者Condition,唤醒指定的线程;
正常输入如下:
······
Producer2生产了value, value的当前值是123
Consumer消费了value, value的当前值是
Producer2生产了value, value的当前值是123
Consumer消费了value, value的当前值是
Producer2生产了value, value的当前值是123
Consumer消费了value, value的当前值是
Producer1生产了value, value的当前值是123
Consumer消费了value, value的当前值是
Producer1生产了value, value的当前值是123
Consumer消费了value, value的当前值是
Producer1生产了value, value的当前值是123
Consumer消费了value, value的当前值是
Producer1生产了value, value的当前值是123
Consumer消费了value, value的当前值是
Producer1生产了value, value的当前值是123
Consumer消费了value, value的当前值是
······
Java多线程(九):生产者消费者模型的更多相关文章
- java多线程之生产者消费者模型
public class ThreadCommunication{ public static void main(String[] args) { Queue q = new Queue();//创 ...
- 第23章 java线程通信——生产者/消费者模型案例
第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...
- java多线程解决生产者消费者问题
import java.util.ArrayList; import java.util.List; /** * Created by ccc on 16-4-27. */ public class ...
- java多线程模拟生产者消费者问题,公司面试常常问的题。。。
package com.cn.test3; //java多线程模拟生产者消费者问题 //ProducerConsumer是主类,Producer生产者,Consumer消费者,Product产品 // ...
- java 线程池、多线程实战(生产者消费者模型,1 vs 10) 附案例源码
导读 前二天写了一篇<Java 多线程并发编程>点我直达,放国庆,在家闲着没事,继续写剩下的东西,开干! 线程池 为什么要使用线程池 例如web服务器.数据库服务器.文件服务器或邮件服务器 ...
- C++11 并发指南九(综合运用: C++11 多线程下生产者消费者模型详解)
前面八章介绍了 C++11 并发编程的基础(抱歉哈,第五章-第八章还在草稿中),本文将综合运用 C++11 中的新的基础设施(主要是多线程.锁.条件变量)来阐述一个经典问题——生产者消费者模型,并给出 ...
- Java里的生产者-消费者模型(Producer and Consumer Pattern in Java)
生产者-消费者模型是多线程问题里面的经典问题,也是面试的常见问题.有如下几个常见的实现方法: 1. wait()/notify() 2. lock & condition 3. Blockin ...
- 进程,线程,GIL,Python多线程,生产者消费者模型都是什么鬼
1. 操作系统基本知识,进程,线程 CPU是计算机的核心,承担了所有的计算任务: 操作系统是计算机的管理者,它负责任务的调度.资源的分配和管理,统领整个计算机硬件:那么操作系统是如何进行任务调度的呢? ...
- Java多线程_生产者消费者模式1
生产者消费者模型 具体来讲,就是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品.生产消费者模式如下图.(图片来自网络 ...
- JAVA多线程之生产者 消费者模式 妈妈做面包案例
创建四个类 1.面包类 锅里只可以放10个面包 ---装面包的容器2.厨房 kitchen 生产面包 和消费面包 最多生产100个面包3.生产者4消费者5.测试类 多线程经典案例 import ja ...
随机推荐
- 多项式fft、ntt、fwt 总结
做了四五天的专题,但是并没有刷下多少题.可能一开始就对多项式这块十分困扰,很多细节理解不深. 最简单的形式就是直接两个多项式相乘,也就是多项式卷积,式子是$N^2$的.多项式算法的过程就是把卷积做一种 ...
- Spring事务知识点
事务的传播属性 PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中.// 最常用,@Transactional注解默认 PROPAGA ...
- 【Java/MySql】使用JDBC访问MySql数据库的Maven工程
下载链接:https://files.cnblogs.com/files/xiandedanteng/FindNotnullColumns20191102-1.rar pom.xml里写: <p ...
- P2047 [NOI2007]社交网络(洛谷)
题目描述 在社交网络 ( Social Network ) 的研究中,我们常常使用图论概念去解释一些社会现象.不妨看这样的一个问题:在一个社交圈子里有 nn 个人,人与人之间有不同程度的关系.我们将这 ...
- 《你不知道的JavaScript(上)》笔记——词法作用域
词法作用域是一套关于引擎如何寻找变量以及会在何处找到变量的规则. 词法作用域最重要的特征是它的定义过程发生在代码的书写阶段(假设你没有使用eval() 或 with) 欺骗词法:指修改词法作用域, 欺 ...
- SQLW3School-高级:SQL TOP 子句
ylbtech-SQLW3School-高级:SQL TOP 子句 1.返回顶部 1. TOP 子句 TOP 子句用于规定要返回的记录的数目. 对于拥有数千条记录的大型表来说,TOP 子句是非常有用的 ...
- 用jeecg做个项目第二讲(Datagrid数据列表效果详解)
1.列表界面 2.流程状态的效果 <t:dgCol title="流程状态" field="bpmStatus" queryMode="sing ...
- delphi type
声明: 1. type Name = Existing type; 2. type Name = type Existing type; 3. type Name = (EnumValue1 [=va ...
- 【error】 for i in range(len(shape)/2): TypeError: 'float' object cannot be interpreted as an integer
Q: for i in range(len(shape)/2):TypeError: 'float' object cannot be interpreted as an integer A: for ...
- Linux磁盘和文件系统扩容彻底研究
1.物理卷: LVM 逻辑卷的底层物理存储单元是一个块设备,比如一个分区或整个磁盘.要在 LVM 逻辑卷中使用该设备,则必须将该设备初始化为物理卷(PV). 2.卷组:物理卷合并为卷组(VG).这样就 ...