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. java 几个线程池的理解

    http://www.cnblogs.com/dolphin0520/p/3932921.html 这个文章写的很好

  2. div下拉框(待改善)

    不说话,直接上代码,其中函数dealchose()没有实现,各位就不必纠结了 <%@ page language="java" import="java.util. ...

  3. JavaScript中推断一个对象是否为&quot;空对象”

    JavaScript中推断一个对象是否为"空对象" 这里指的"空对象"是类似于:{ } 和 new Object() 这种. 详细的代码实现和原理例如以下: / ...

  4. apue学习笔记(第十四章 高级I/O)

    本章涵盖了从多概念和函数:非阻塞I/O.记录锁.I/O多路转换.异步I/O.readv和writev函数以及存储映射I/O 非阻塞I/O 非阻塞I/O使我们可以发出open.read和write这样的 ...

  5. VueJS计算属性: computed

    computed属性 HTML <!DOCTYPE html> <html> <head> <meta charset="utf-8"&g ...

  6. vscode Js 插件 Jshint 的配置

    vscode这款编辑器让人用起来很舒服,但是刚刚入手的童鞋可能会对其插件的安装产生一些恐惧,虽然vscode提供了插件的搜索和安装,但是其中一些插件是需要一些软件或者包之类的东西做支撑的,并不是在vs ...

  7. nginx配置:支持phpfastcgi,nginx和php-cgi通信,部分nginx常量解释

    支持phpfastcgi的配置如下: server { listen 8000; server_name localhost; root F:/home/projects/test; index in ...

  8. BCG菜单button的简单使用

    一,新建一个BCGprojectCBCGPMenuButton,基于对话框. 二.添加一个button,并关联一个CButton类型的变量m_btn1.然后手动将类型改CBCGPMenuButton成 ...

  9. mysql 让一个存储过程定时作业的代码(转)

    1.在mysql 中建立一个数据库 test1 语句:create database test1 2.创建表examinfo create table examinfo( id int auto_in ...

  10. 用C语言解决迷宫问题

    #include <stdio.h> #include <stdlib.h> #define ROW 10 #define COL 10 /*迷宫中位置信息*/ typedef ...