前言:最近在学习Java多线程,看到ImportNew网上有网友翻译的一篇文章《阻塞队列实现生产者消费者模式》。在文中,使用的是Java的concurrent包中的阻塞队列来实现。在看完后,自行实现阻塞队列。

(一)准备

  在本博文中,没有使用concurrent包中提供的阻塞队列,而是基于最近对多线程的学习,使用了ReentrantLock,开发实现了阻塞队列。如果想参考concurrent包中阻塞队列的使用方式,请点击上面的连接。

  在多线程中,生产者-消费者问题是一个经典的多线程同步问题。简单来说就是有两种线程(在这里也可以做进程理解)——生产者和消费者,他们共享一个固定大小的缓存区(如一个队列)。生产者负责产生放入新数据,消费者负责取出缓存区的数据。具体介绍请参考 Producer-consumer problem

(二)设计概述

  详细的代码可以到我的 Github 仓库下载(master分支为详细的代码,输出所有的必要信息;simplification分支为简化的代码)。

  项目代码,分为四个类:Consumer类为消费者线程,Producer类为生产者线程,ProducerConsumer测试的启动类,ProducerConsumerQueue类为阻塞队列。

  在多线程中,生产者不断向队列放入新数据,当队列已满时,生产者将被阻塞,直到消费者从队列中取出部分数据并唤醒生产者;消费者不断从队列取出数据,当队列为空时,消费者将被阻塞,直到生产者再次放入新数据并唤醒消费者。在JAVA的concurrent包中,提供了一系列阻塞队列帮我们完成这一工作。这一工作也恰好是生产者消费者的问题的关键所在。在这里,我将自行实现阻塞队列:ProducerConsumerQueue;

(三)详细实现

  (1)ProducerConsumerQueue类

 public final class ProducerConsumerQueue<E> {
//声明一个重入锁
private final Lock lock = new ReentrantLock();
private final Condition notEmpty = lock.newCondition();
private final Condition notFull = lock.newCondition();
//缓存大小
private final int CAPACITY;
//存储数据的缓存队列
private Queue<E> queue; public ProducerConsumerQueue(int CAPACITY) {
this.CAPACITY = CAPACITY;
this.queue = new LinkedList<E>();
} //put the e into the queue
public void put(E e) throws InterruptedException {
lock.lock(); try {
while (queue.size() == this.CAPACITY)
this.notFull.await();
queue.offer(e);
this.notEmpty.signalAll();
} finally {
lock.unlock();
}
} //get e from queue.
public E take() throws InterruptedException {
lock.lock(); try {
while (queue.size() == 0)
this.notEmpty.await();
this.notFull.signalAll();
return queue.poll();
} finally {
lock.unlock();
}
}
}

  该队列提供put()和take()方法,前者用于生产者放入数据,后者用于消费者取出数据。

  在put方法中,首先要获得锁。然后检测是否队列已满,如果是,阻塞生产者线程,并释放锁;当再次获得锁时,这里使用了while语句,使得线程再次检查队列是否已满,如果未满,放入数据到缓存,并唤醒可能阻塞的消费者线程。在这里使用while,目的是防止其他生产者线程已经唤醒,并且成功放入新数据到队列,然后阻塞,而该线程又再次放入,导致可能缓存溢出。

  在take方法中,同样要先获得锁。检测队列是否已空,如果是,阻塞消费者线程,释放锁;当被唤醒并再次获得锁时,使用while再次检查队列是否仍为空,如果非空,则取出缓存数据。while同样为了防止其他消费者对一个空队列取数据。

  (2)Consumer类

 public class Consumer implements Runnable {
private final ProducerConsumerQueue sharedQueue; public Consumer(ProducerConsumerQueue sharedQueue) {
this.sharedQueue = sharedQueue;
} @Override
public void run() {
while (true) {
try {
synchronized (this){
System.out.println("\tConsumer: " + sharedQueue.take());
}
} catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName() + " throw a interrupexception.");
//do something.
}
}
}
}

  消费者线程持续从队列中取出数据。

  (3)Producer类

 public class Producer implements Runnable {
private final ProducerConsumerQueue sharedQueue; public Producer(ProducerConsumerQueue sharedQueue) {
this.sharedQueue = sharedQueue;
} @Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
synchronized (this){
System.out.println("Producer: "+i);
sharedQueue.put(i);
}
} catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName() + " throw a interrupexception. ");
//do something.
}
}
}
}

  生产者线程产生数据并放入队列中。

  (4)ProducerConsumer测试类

public class ProducerConsumer {
public static void main(String[] args) {
ProducerConsumerQueue sharedQueue = new ProducerConsumerQueue(4); Thread prodThread = new Thread(new Producer(sharedQueue));
Thread consThread1 = new Thread(new Consumer(sharedQueue));
Thread consThread2 = new Thread(new Consumer(sharedQueue)); prodThread.start();
consThread1.start();
consThread2.start();
}
}

  创建一个生产者线程和两个消费者线程。

扩展:

1、Wikipedia:http://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem

2、《聊聊并发——生产者和消费者模式》http://www.infoq.com/cn/articles/producers-and-consumers-mode

Java 多线程学习笔记:生产者消费者问题的更多相关文章

  1. Java多线程学习笔记--生产消费者模式

    实际开发中,我们经常会接触到生产消费者模型,如:Android的Looper相应handler处理UI操作,Socket通信的响应过程.数据缓冲区在文件读写应用等.强大的模型框架,鉴于本人水平有限目前 ...

  2. java多线程学习笔记——详细

    一.线程类  1.新建状态(New):新创建了一个线程对象.        2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中, ...

  3. JAVA多线程学习笔记(1)

    JAVA多线程学习笔记(1) 由于笔者使用markdown格式书写,后续copy到blog可能存在格式不美观的问题,本文的.mk文件已经上传到个人的github,会进行同步更新.github传送门 一 ...

  4. Java多线程学习笔记(一)——多线程实现和安全问题

    1. 线程.进程.多线程: 进程是正在执行的程序,线程是进程中的代码执行,多线程就是在一个进程中有多个线程同时执行不同的任务,就像QQ,既可以开视频,又可以同时打字聊天. 2.线程的特点: 1.运行任 ...

  5. Java多线程学习笔记

    进程:正在执行中的程序,其实是应用程序在内存中运行的那片空间.(只负责空间分配) 线程:进程中的一个执行单元,负责进程汇总的程序的运行,一个进程当中至少要有一个线程. 多线程:一个进程中时可以有多个线 ...

  6. Java多线程-并发协作(生产者消费者模型)

    对于多线程程序来说,不管任何编程语言,生产者和消费者模型都是最经典的.就像学习每一门编程语言一样,Hello World!都是最经典的例子. 实际上,准确说应该是“生产者-消费者-仓储”模型,离开了仓 ...

  7. JAVA多线程经典问题 -- 生产者 消费者

    工作2年多来一直也没有计划写自己的技术博客,最近辞职在家翻看<thingking in JAVA>,偶尔看到了生产者与消费者的一个经典的多线程同步问题.本人在工作中很少使用到多线程以及高并 ...

  8. java 多线程 22 :生产者/消费者模式 进阶 利用await()/signal()实现

    java多线程15 :wait()和notify() 的生产者/消费者模式 在这一章已经实现了  wait/notify 生产消费模型 利用await()/signal()实现生产者和消费者模型 一样 ...

  9. java多线程学习笔记(四)

    上一节讲到Synchronized关键字,synchronized上锁的区域:对象锁=方法锁/类锁 本节补充介绍一下synchronized锁重入: 关键字synchronized拥有锁重入的功能,也 ...

随机推荐

  1. BZOJ 4765 普通计算姬 (分块 + BIT)

    4765: 普通计算姬 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 1547  Solved: 329[Submit][Status][Discus ...

  2. 【20171101】the first day in a new company

    英文差的要命还飙英文,擦嘞!!! 就是想记录下 点滴 如下配图: | | | V 手动配图这是图!!!

  3. noip第21课作业

    1. 遍历二叉树 [问题描述] 以先序的方式建立一棵二叉树,空结点用‘#’号表示,例如:abd###ce##f##,将建立一棵如下的二叉树: 输出其中序序列和后序序列,其中总结点个数不超过100. 输 ...

  4. 第85讲:Scala中For表达式的强大表现力实战

    今天来学一下scala中的For表达式的用法. package scala.learn case class Persons(name:String,isMale:Boolean,children:P ...

  5. lca tarjin

    这个算法  我个人认为是  遍历每一个点把它当成一些询问的最近祖先 1 2 3 4 5 6 low是并差集,vis是是否访问过,访问过为true,没有为false: 假设询问是(4,4),(4,5), ...

  6. POJ 2570 线段树

    Potted Flower Time Limit: 2000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u Jav ...

  7. 1.Django入门

    MVC 大部分开发语言中都有MVC框架 MVC框架的核心思想是:解耦 降低各功能模块之间的耦合性,方便变更,更容易重构代码,最大程度上实现代码的重用 m表示model,主要用于对数据库层的封装 v表示 ...

  8. cxgrid回车移到下一个单元格

    cxgrid回车移到下一个单元格   cxgrid回车移到下一个单元格 作用:表格式录入全键盘操作. 设置cxgrid1Dbtableview1.optionsBehavior.goToNextCel ...

  9. Android-available for offline mode

    出现 available for offline mode 字样的异常: 取消打钩 Offine work 点击sync project ..... 成功解决:

  10. Constructor in depth

    There are two types of constructor:Instance Constructor and Type Constructor(or so-called Static Con ...