Java多线程基础:生产者/消费者模型

生产者/消费者模型

  生产者消费者模型是多线程协作的经典模型,生产者线程负责产出数据,消费者线程负责消费生产者生产的数据,数据存放在共享区域内。该模型旨在合理的指导生产者和消费者进行生产或消费,避免过量生产以及无法消费的等问题。

  

 首先生产者和消费者互相解耦,那线程同步的重任放在了共享区域内:

  • 当共享区域存满时,阻塞生产者,防止其继续生产。
  • 当共享区域清空时,阻塞消费者,防止其继续消费。   

说明:这里的阻塞并不等同指线程的阻塞态,实现阻塞的方式有很多种 。 

  1. 线程调用sleep。
  2. 线程调用阻塞式IO方法,在该方法返回前,该线程被阻塞。
  3. 线程试图获得一个同步监视器,但该同步监视器正在被其他线程所持有。
  4. 线程等待某个通知。
  5. 程序调用了suspend方法将该线程挂起,非常容易导致死锁,避免即可。 

基于等待/唤醒机制实现模型

实现原理

  object.wait()方法的作用是使当前执行代码的线程进入等待态,该方法用来将当前线程置入“预执行队列”,并在wait所在的代码行处停止执行,直到接到通知或被中断为止。wait方法会释放锁,所以它一定是在同步方法或同步代码块中使用。

  obejct.notify()方法也是在同步方法或者同步块中使用,该方法用于通知那些可能等待该对象的对象锁的其他线程,如果有多个线程等待,则由线程规划器随机挑选出其中一个呈wait状态的线程,对其发出通知notify,并使它等待获取该对象的对象锁。

说明:在执行notify方法后,当前线程不会马上释放该对象锁,呈wait状态的线程也并不能马上获取该对象锁,要等到执行notify方法的线程将程序执行完,也就是退出Synchronized代码块后,才会释放锁,而呈wait状态所在的线程才可以获取该对象锁

  一句话总结就是:wait是线程停止运行,已达到阻塞的目的,而notify使停止的线程继续运行。它们两个互相配合,以实现线程间相互通信

代码实现

生产者,负责生产数据。

class Producer extends Thread{
private Buffer buffer;
public Producer(Buffer buffer){
this.buffer = buffer;
}
@Override
public void run() {
for (int i=0;i<10;i++){
try {
buffer.add(i);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

消费者,负责消费数据。

class Consumer extends Thread{
private Buffer buffer;
public Consumer(Buffer buffer){
this.buffer = buffer;
}
@Override
public void run() {
for(int i=0;i<10;i++){
try {
System.out.println(buffer.pull());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

缓存区,即共享区域。

class Buffer{
private Queue<Integer> list;
private int size; public Buffer(int size) {
list = new LinkedList<>();
this.size = size;
} public void add(int val) throws InterruptedException {
synchronized (this){
if(list.size()>=size)
wait();
list.add(val);
notify();
}
} public int pull() throws InterruptedException {
synchronized (this){
if(list.size()==0)
wait();
int val = list.poll();
notify();
return val;
}
} }

  

参考资料

  • 《Java多线程编程艺术》

Java基础教程:多线程基础(3)——阻塞队列的更多相关文章

  1. Java中常用的七个阻塞队列介绍第一篇

    Java中常用的七个阻塞队列介绍第一篇 在上一篇我们对Java中的队列分类做了简单的介绍.本文咱们主要来聊聊阻塞队列中的七个常用子类.这七个阻塞队列的学习步骤:先看源码,分析完源码之后,我们再来对每个 ...

  2. Java中常用的七个阻塞队列第二篇DelayQueue源码介绍

    Java中常用的七个阻塞队列第二篇DelayQueue源码介绍 通过前面两篇文章,我们对队列有了了解及已经认识了常用阻塞队列中的三个了.本篇我们继续介绍剩下的几个队列. 本文主要内容:通过源码学习De ...

  3. Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍

    1.什么是阻塞队列? 所谓队列,遵循的是先进先出原则(FIFO),阻塞队列,即是数据共享时,A在写数据时,B想读同一数据,那么就将发生阻塞了. 看一下线程的四种状态,首先是新创建一个线程,然后,通过s ...

  4. Java多线程-新特征-阻塞队列ArrayBlockingQueue

    阻塞队列是Java5线程新特征中的内容,Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue,阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素 ...

  5. java多线程8:阻塞队列与Fork/Join框架

    队列(Queue),是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的. BlockingQueue 而阻塞队列BlockingQueue除了继承 ...

  6. java多线程系列10 阻塞队列模拟

    接下来的几篇博客会介绍下juc包下的相关数据结构 包含queue,list,map等 这篇文章主要模拟下阻塞队列. 下面是代码 import java.util.LinkedList; import ...

  7. java中的多线程 // 基础

    java 中的多线程 简介 进程 : 指正在运行的程序,并具有一定的独立能力,即 当硬盘中的程序进入到内存中运行时,就变成了一个进程 线程 : 是进程中的一个执行单元,负责当前程序的执行.线程就是CP ...

  8. Java设计模式—生产者消费者模式(阻塞队列实现)

    生产者消费者模式是并发.多线程编程中经典的设计模式,生产者和消费者通过分离的执行工作解耦,简化了开发模式,生产者和消费者可以以不同的速度生产和消费数据.这篇文章我们来看看什么是生产者消费者模式,这个问 ...

  9. Java并发编程(十)阻塞队列

    使用非阻塞队列的时候有一个很大问题就是:它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,就必须额外地实现同步策略以及线程间唤醒策略,这个实现起来就非常麻烦.但是有了阻塞队列就不一样了, ...

  10. Java并发(7):阻塞队列

    在前面我们接触的队列都是非阻塞队列,比如PriorityQueue.LinkedList(LinkedList是双向链表,它实现了Dequeue接口). 使用非阻塞队列的时候有一个很大问题就是:它不会 ...

随机推荐

  1. Fresco,Facbook强大的图片加载框架

    项目git地址:https://github.com/facebook/fresco Fresco是 facebook推出的一款强大的图片加载的框架:主要有Image Pipeline和Drawees ...

  2. 通过run configuration启动项目

    系统通过配置加载路径是通过classpath加载绝对路径 设置属性选中某个项目,然后在工具栏中选择"Run-->Run Confgurations“,然后在对话框的右边选择" ...

  3. 【开发总结】—— BABYLON 项目开发必备系列

    前言:在公司主要使用Babylon.js作为前端引擎,我自己在开发中总结到基本上每一个新项目都会需要这些基本设置. 一.ios兼容:解决镜面反射   如果不加offline,材质中有镜面反射,苹果手机 ...

  4. Linux:和任务执行相关的 【批命令执行 runparts 】命令

    run-parts:执行目录下的 命令或脚本 工具,其他非可执行文件和子目录下的文件不会被执行.目录下的命令,是以基本的词汇(字符)顺序执行的,除非你指定了--reverse 逆序选项!这是个老牌的G ...

  5. linux中expr用法

    名称:expr  ### 字串长度  shell>> expr length "this is a test"  14  ### 数字商数  shell>> ...

  6. 微信小程序 - 下载图片并且显示进度

    lastUpDate: 2018-8-12 请把请求地址加入到downLoadFile 提示:首先得要在公众号设置对应的downLoadFile地址. downImg : 下载图片 wxml js d ...

  7. 【设计模式】工厂方法(FactoryMethod)模式

    看不见PPT的请自行解决DNS污染问题. 相关类的代码: namespace FactoryPatternConsole.Model { public class Address { public s ...

  8. vuex 中关于 mapActions 的作用

    mapActions 工具函数会将 store 中的 dispatch 方法映射到组件的 methods 中.和 mapState.mapGetters 也类似,只不过它映射的地方不是计算属性,而是组 ...

  9. 生成二维码 加密解密类 TABLE转换成实体、TABLE转换成实体集合(可转换成对象和值类型) COOKIE帮助类 数据类型转换 截取字符串 根据IP获取地点 生成随机字符 UNIX时间转换为DATETIME\DATETIME转换为UNIXTIME 是否包含中文 生成秘钥方式之一 计算某一年 某一周 的起始时间和结束时间

    生成二维码 /// <summary>/// 生成二维码/// </summary>public static class QRcodeUtils{private static ...

  10. cocos2dx-3.0(8)------Label、LabelTTF、LabelAtlas、LabelBMFont使用之法

    ----我的生活,我的点点滴滴!! 最后一个LabelBMFont了,字体图集LabelBMFont,LabelBMFont类是一个基于位图的字体图集.是一个包括全部你须要于坐标数据一起显示在屏幕上的 ...