方法1:最简单--利用LinkedBlockingQueue

队列具有先进先出的特点,成为经常应用于生产-消费者模式的数据结构。
1.将一个对象放到队列尾部,如果队列已满,就等待直到有空闲节点。 ——put()方法
2.从队列头部取一个对象,如果没有对象,就等待直到有对象可取。 ——take()方法
3.在存取队列的过程中,锁定队列对象,不允许其它线程访问队列。——使得它是线程安全的

下面的代码适用于多个生产者、多个消费者。

 //Producer.java
import java.util.concurrent.BlockingQueue; /*
* Usage example, based on a typical producer-consumer scenario.
* Note that a <tt>BlockingQueue</tt> can safely be used with multiple
* producers and multiple consumers.
* <pre>
*/
class Producer implements Runnable {
private BlockingQueue<Object> queue; Producer(BlockingQueue<Object> q) {
queue = q;
} public void run() {
try {
while (true) {
queue.put(produce());
Thread.sleep(1);
System.out.println("+1 Produce an Object:" + "生产者size:"
+ queue.size());
}
} catch (InterruptedException ex) {
System.out.println("生产者结束!");
}
} Object produce() {
return new Object();
}
}

Pruducer.java

 //Consumer.java
import java.util.concurrent.BlockingQueue; class Consumer implements Runnable {
private BlockingQueue<Object> queue; Consumer(BlockingQueue<Object> q) {
queue = q;
} public void run() {
try {
while (true) {
consume(queue.take());
Thread.sleep(10);
System.out.println("-1 Consumer an Object:" + "size:"+ queue.size());
}
} catch (InterruptedException ex) {
System.out.println("消费者结束!");
}
} void consume(Object x) {
}
}

Consumer.java

 import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; class Main {
public static void main(String[] args) {
BlockingQueue<Object> q = new LinkedBlockingQueue<Object>();// SomeQueueImplementation();
Producer p = new Producer(q);
Consumer c1 = new Consumer(q);
Consumer c2 = new Consumer(q);
Thread pth = new Thread(p);
pth.start();
new Thread(c1).start();
new Thread(c2).start();
try {
Thread.sleep(50);
pth.interrupt();
} catch (InterruptedException e) {
}
}
}

Main.java

方法2:不采用BlockingQueue,利用lock、Condition来实现

思路:

利用可重用的LinkedList来存放资源,生产者addLast(),消费者removeFirst()。

使用ReentrantLock()来实现消费者和生产者的同步;//可重用的互斥锁

思考:为什么使用了lock后,还使用了它的2个newCondition,这样做有什么好处?

 import java.util.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class ProducerConsumer {
private static final LinkedList<Integer> buffer = new LinkedList<Integer>();
private static final int BUFFERSIZE = 10;
private static Lock lock = new ReentrantLock();//可重用的互斥锁
private static Condition NotFull = lock.newCondition();
private static Condition NotEmpty = lock.newCondition(); static class Producer extends Thread {
public void run() {
while (true) {
// lock
lock.lock();
if (buffer.size() == BUFFERSIZE) {
System.out.println("BUffer is fulls");
try {
NotFull.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
buffer.addLast(1);
NotEmpty.signal();
}
lock.unlock();
// unlock
}
}
} static class Consumer extends Thread {
public void run() {
while (true) {
// lock
lock.lock();
if (buffer.size() == 0) {
System.out.println("BUffer is empty");
try {
NotEmpty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
buffer.removeFirst();
NotFull.signal();
}
// unlock
lock.unlock();
}
}
} public static void main(String[] args){
new Consumer().start();
new Producer().start();
}
}

ProducerConsumer .java

关于Java线程的lock、condition、synchronized的小小总结:

1.synchronized简单易用,但是功能受局限,无法满足复杂的同步机制,比如“读者写者问题”:多个读者线程是不互斥的。

2.lock以更优雅的方式来解决线程同步,比如读写锁ReadWriteLock。

3.Condition解决线程间通信,为不同的线程建立不同的条件。

推荐博文:Java线程-锁机制

Condition可以替代传统的线程间通信,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll()。

——为什么方法名不直接叫wait()/notify()/nofityAll()?因为Object的这几个方法是final的,不可重写!

Condition实现了BlockingQueue的功能。

看看BlockingQueue的继承和实现。

一般的锁Lock的实现:注意ReadLock、WriteLock是内部的静态类,只有ReentrantReadWriteLock类可以调用。

读写的锁ReadWriteLock

思考:OS的信号量是什么,线程通信的方式有哪些?共享变量和消息传递。

信号量与互斥锁有什么联系?

参考资料

By BYRHuangQiang2014-03-18 09:05:30

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

  1. Java实现生产者消费者问题与读者写者问题

    摘要: Java实现生产者消费者问题与读者写者问题 1.生产者消费者问题 生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从 ...

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

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

  3. java实现生产者消费者问题

    引言 生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况: 生产者消费者图 ...

  4. java实现生产者消费者问题(转)

    引言 生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况: 生产者消费者图 ...

  5. [转载] Java实现生产者消费者问题

    转载自http://www.cnblogs.com/happyPawpaw/archive/2013/01/18/2865957.html 引言 生产者和消费者问题是线程模型中的经典问题:生产者和消费 ...

  6. java实现生产者消费者模式

    生产者消费者问题是一个著名的线程同步问题,该问题描述如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个具有多个缓冲区的缓冲池,生产者将 ...

  7. java 线程 生产者-消费者与队列,任务间使用管道进行输入、输出 解说演示样例 --thinking java4

    package org.rui.thread.block2; import java.io.BufferedReader; import java.io.IOException; import jav ...

  8. Java 实现生产者 – 消费者模型

    转自:http://www.importnew.com/27063.html 考查Java的并发编程时,手写“生产者-消费者模型”是一个经典问题.有如下几个考点: 对Java并发模型的理解 对Java ...

  9. Java——Java实现生产者消费者

    1.生产/消费者模型 生产/消费者问题是个非常典型的多线程问题,涉及到的对象包括"生产者"."消费者"."仓库"和"产品" ...

  10. java多线程 生产者消费者模式

    package de.bvb; /** * 生产者消费者模式 * 通过 wait() 和 notify() 通信方法实现 * */ public class Test1 { public static ...

随机推荐

  1. popupWindow使用详解

    popupWindow说起来简单,但是使用略麻烦,今天带大家来看看怎么使用,先来看看效果图: 先来看看布局文件吧: <RelativeLayout xmlns:android="htt ...

  2. android自定义控件之滚动广告条

    在一些电子商务网站上经常能够看到一些滚动的广告条,许多软件在首次使用时也有类似的广告条,如图: 其实在github上有实现这种效果的控件,不过这东西做起来也是很简单,我们今天就来看看该怎么做. 先来看 ...

  3. samba环境搭建

    1.安装samba软件 sudo apt-get install samba cifs-utils samba-common 2.创建与windows共享目录 mkdir share chmod 77 ...

  4. tomcat中jsp编译

    tomcat运行的工程中,jsp替换文件后可能不起作用.原因是jsp也是需要编译的.编译后的文件存放在tomcat/work文件夹下.如果替换不起作用,可以将work文件夹下的内容删除掉,重新启tom ...

  5. Java中OutOfMemoryError(内存溢出)的情况及解决办法

    java.lang.OutOfMemoryError: Java heap space // TODO Auto-generated method stub Vector v = new Vector ...

  6. C#调用ActiveX控件

    背景:最近项目中需要用到ActiveX控件,项目是在.Net平台下开发的.因此就直接在项目中添加了对ActiveX控件的引用,添加引用成功.在代码中实例化类的实例也没有问题,但在调用其方法或属性时总是 ...

  7. ios framework通用库的制作

    这篇文章是在史上最完整的iOS DIY framework 详细教程(一)的基础上加以修改 1.新建一个静态库工程: 2:取自己喜欢的名字: 3.删除向导所生成工程中的 Target: 3.删除Tes ...

  8. c#equals相关

    1.==是直接比较值类型的值或引用类型的引用地址,但==不能用于struct,struct只能用equals来比较.==一般情况下与object.equals得到的结果是相等的. 2.Referenc ...

  9. ios专题 - APP设计流程

    网上看到这篇文章,觉得基本的flow很有帮助,转过来收藏了:作者:关于Sarah Parmenter英国艾塞克斯(英国英格兰东南部的郡)Youknowwho设计工作室的创始人,Sarah Parmen ...

  10. jQuery easyUI框架中经常出现的问题

    相信开发者对于我们jquery来说都不会陌生吧,jquery为我们的开发提供了很多各式各样的库,满足各种开发的需求,其中我们知道的有轻量级的,但是也有一些基于富客服端的一些重量级库,顾名思义,当我们在 ...