java 多线程并发系列之 生产者消费者模式的两种实现
2018-01-15 22:47
531 查看
生产者消费者模式是并发、多线程编程中经典的设计模式,生产者和消费者通过分离的执行工作解耦,简化了开发模式,生产者和消费者可以以不同的速度生产和消费数据。
真实世界中的生产者消费者模式
生产者和消费者模式在生活当中随处可见,它描述的是协调与协作的关系。比如一个人正在准备食物(生产者),而另一个人正在吃(消费者),他们使用一个共用的桌子用于放置盘子和取走盘子,生产者准备食物,如果桌子上已经满了就等待,消费者(那个吃的)等待如果桌子空了的话。这里桌子就是一个共享的对象。
我们看这样一个例子:
生产者: 往一个公共的盒子里面放苹果
消费者:从公共的盒子里面取苹果
盒子:盒子的容量不能超过5
下面我们用两者方法分别实现这样一个场景。
方法一: wait() 和 notify() 通信方法实现
看盒子代码
public class PublicBox
{
private int apple =
0;
public synchronized void increace()
{
while (apple ==5)
{
[align=left] try { [/align]
[align=left] wait(); [/align]
} catch (InterruptedException
e) {
[align=l
4000
eft] e.printStackTrace(); [/align]
[align=left] } [/align]
[align=left] [/align]
[align=left] } [/align]
[align=left] apple++; [/align]
[align=left] System. out .println("生成苹果成功!" );[/align]
[align=left] notify(); [/align]
[align=left] } [/align]
public synchronized void decreace()
{
while (apple ==0)
{
[align=left] try { [/align]
[align=left] wait(); [/align]
} catch (InterruptedException
e) {
[align=left] e.printStackTrace(); [/align]
[align=left] } [/align]
[align=left] } [/align]
[align=left] apple--; [/align]
[align=left] System. out.println( "消费苹果成功!" );[/align]
[align=left] notify(); [/align]
[align=left] } [/align]
[align=left] [/align]
public static void main(String
[]args)
[align=left] {[/align]
[align=left] PublicBox box= new PublicBox();[/align]
[align=left] [/align]
[align=left] Consumer con= new Consumer(box);[/align]
[align=left] Producer pro= new Producer(box);[/align]
[align=left] [/align]
[align=left] Thread t1= new Thread(con);[/align]
[align=left] Thread t2= new Thread(pro);[/align]
[align=left] [/align]
[align=left] t1.start();[/align]
[align=left] t2.start();[/align]
[align=left] [/align]
[align=left] [/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] [/align]
生产者代码(定义十次):
public class Producer implements Runnable
{
[align=left] private PublicBox box; [/align]
[align=left] [/align]
public Producer(PublicBox
box) {
this .box =
box;
[align=left] } [/align]
[align=left] [/align]
[align=left] @Override [/align]
public void run()
{
for( int i=0;i<10;i++)
[align=left] {[/align]
[align=left] try {[/align]
System. out .println("pro
i:" +i);
[align=left] Thread. sleep(30);[/align]
} catch (InterruptedException
e) {
// TODO:
handle exception
[align=left] e.printStackTrace();[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] box.increace(); [/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] } [/align]
[align=left]}[/align]
消费者代码(同样十次):
[align=left][/align]
public class Consumer implements Runnable
{
[align=left] private PublicBox box; [/align]
[align=left] [/align]
public Consumer(PublicBox
box) {
this .box =
box;
[align=left] } [/align]
[align=left] [/align]
[align=left] @Override [/align]
public void run()
{
[align=left] [/align]
[align=left] for( int i=0;i<10;i++)[/align]
[align=left] {[/align]
[align=left] try {[/align]
System. out .println("Con:
i " +i);
Thread. sleep(3000);
// 这里设置跟上面30不同是为了 盒子中的苹果能够增加,不会生产一个马上被消费
} catch (InterruptedException
e) {
// TODO:
handle exception
[align=left] e.printStackTrace();[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] box.decreace(); [/align]
[align=left] } [/align]
[align=left] } [/align]
[align=left]}[/align]
[align=left] [/align]
输出如下:
[align=left]pro i:0[/align]
[align=left]Con: i 0[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:1[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:2[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:3[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:4[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:5[/align]
[align=left]消费苹果成功![/align]
[align=left]Con: i 1[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:6[/align]
[align=left]消费苹果成功![/align]
[align=left]Con: i 2[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:7[/align]
[align=left]消费苹果成功![/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:8[/align]
[align=left]Con: i 3[/align]
[align=left]消费苹果成功![/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:9[/align]
[align=left]Con: i 4[/align]
[align=left]消费苹果成功![/align]
[align=left]生成苹果成功![/align]
[align=left]Con: i 5[/align]
[align=left]消费苹果成功![/align]
[align=left]Con: i 6[/align]
[align=left]消费苹果成功![/align]
[align=left]Con: i 7[/align]
[align=left]消费苹果成功![/align]
[align=left]Con: i 8[/align]
[align=left]消费苹果成功![/align]
[align=left]Con: i 9[/align]
[align=left]消费苹果成功![/align]
[align=left]
[/align]
方法二:采用阻塞队列实现生产者消费者模式
阻塞队列实现生产者消费者模式超级简单,它提供开箱即用支持阻塞的方法put()和take(),开发者不需要写困惑的wait-nofity代码去实现通信。BlockingQueue 一个接口,Java5提供了不同的现实,如ArrayBlockingQueue和LinkedBlockingQueue,两者都是先进先出(FIFO)顺序。而ArrayLinkedQueue是自然有界的,LinkedBlockingQueue可选的边界。下面这是一个完整的生产者消费者代码例子,对比传统的wait、nofity代码,它更易于理解。
盒子代码:
[align=left]import java.util.concurrent.BlockingQueue;[/align]
[align=left]import java.util.concurrent.LinkedBlockingQueue;[/align]
[align=left]
[/align]
public class PublicBoxQueue
{
[align=left]
[/align]
[align=left] [/align]
public static void main(String
[]args)
[align=left] {[/align]
BlockingQueue publicBoxQueue= new LinkedBlockingQueue(5);
//定义了一个大小为5的盒子
[align=left] [/align]
[align=left] Thread pro= new Thread(new ProducerQueue(publicBoxQueue));[/align]
[align=left] Thread con= new Thread(new ConsumerQueue(publicBoxQueue));[/align]
[align=left] [/align]
[align=left] pro.start();[/align]
[align=left] con.start();[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left]}[/align]
生产者:
[align=left]package dsd;[/align]
[align=left]
[/align]
[align=left]import java.util.concurrent.BlockingQueue;[/align]
[align=left]
[/align]
public class ProducerQueue implements Runnable
{
[align=left]
[/align]
[align=left] private final BlockingQueue proQueue;[/align]
[align=left] [/align]
[align=left] public ProducerQueue(BlockingQueue proQueue)[/align]
[align=left] {[/align]
[align=left] this .proQueue =proQueue;[/align]
[align=left] }[/align]
[align=left]
[/align]
[align=left] @Override[/align]
public void run()
{
// TODO Auto-generated
method stub
[align=left] [/align]
[align=left] for (int i=0;i<10;i++)[/align]
[align=left] {[/align]
[align=left] try {[/align]
System. out .println("生产者生产的苹果编号为
: " +i); //放入十个苹果编号 为1到10
[align=left] proQueue .put(i);[/align]
[align=left] [/align]
[align=left] /*Thread.sleep(3000);*/[/align]
} catch (InterruptedException
e) {
// TODO:
handle exception
[align=left] e.printStackTrace();[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] [/align]
[align=left]}[/align]
消费者:
[align=left]package dsd;[/align]
[align=left]
[/align]
[align=left]import java.util.concurrent.BlockingQueue;[/align]
[align=left]
[/align]
public class ConsumerQueue implements Runnable
{
[align=left]
[/align]
[align=left] private final BlockingQueue conQueue;[/align]
[align=left] [/align]
[align=left] public ConsumerQueue(BlockingQueue conQueue)[/align]
[align=left] {[/align]
[align=left] this .conQueue =conQueue;[/align]
[align=left] }[/align]
[align=left]
[/align]
[align=left] @Override[/align]
public void run()
{
// TODO Auto-generated
method stub
[align=left] for (int i=0;i<10;i++)[/align]
[align=left] {[/align]
[align=left] try {[/align]
System. out .println("消费者消费的苹果编号为
:" +conQueue .take());
[align=left] Thread. sleep(3000); //在这里sleep是为了看的更加清楚些[/align]
[align=left] [/align]
} catch (InterruptedException
e) {
// TODO:
handle exception
[align=left] e.printStackTrace();[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] [/align]
[align=left]}[/align]
[align=left]
[/align]
[align=left]结果如下:[/align]
[align=left]
[/align]
[align=left]生产者生产的苹果编号为 : 0[/align]
[align=left]生产者生产的苹果编号为 : 1[/align]
[align=left]消费者消费的苹果编号为 :0[/align]
[align=left]生产者生产的苹果编号为 : 2[/align]
[align=left]生产者生产的苹果编号为 : 3[/align]
[align=left]生产者生产的苹果编号为 : 4[/align]
[align=left]生产者生产的苹果编号为 : 5[/align]
[align=left]生产者生产的苹果编号为 : 6[/align]
[align=left]生产者生产的苹果编号为 : 7[/align]
[align=left]消费者消费的苹果编号为 :1[/align]
[align=left]消费者消费的苹果编号为 :2[/align]
[align=left]生产者生产的苹果编号为 : 8[/align]
[align=left]消费者消费的苹果编号为 :3[/align]
[align=left]生产者生产的苹果编号为 : 9[/align]
[align=left]消费者消费的苹果编号为 :4[/align]
[align=left]消费者消费的苹果编号为 :5[/align]
[align=left]消费者消费的苹果编号为 :6[/align]
[align=left]消费者消费的苹果编号为 :7[/align]
[align=left]消费者消费的苹果编号为 :8[/align]
[align=left]消费者消费的苹果编号为 :9[/align]
生产者消费者模式的好处
它的确是一种实用的设计模式,常用于编写多线程或并发代码。下面是它的一些优点:
它简化的开发,你可以独立地或并发的编写消费者和生产者,它仅仅只需知道共享对象是谁
生产者不需要知道谁是消费者或者有多少消费者,对消费者来说也是一样
生产者和消费者可以以不同的速度执行
分离的消费者和生产者在功能上能写出更简洁、可读、易维护的代码
转自http://blog.csdn.net/yujin753/article/details/45723175
真实世界中的生产者消费者模式
生产者和消费者模式在生活当中随处可见,它描述的是协调与协作的关系。比如一个人正在准备食物(生产者),而另一个人正在吃(消费者),他们使用一个共用的桌子用于放置盘子和取走盘子,生产者准备食物,如果桌子上已经满了就等待,消费者(那个吃的)等待如果桌子空了的话。这里桌子就是一个共享的对象。
我们看这样一个例子:
生产者: 往一个公共的盒子里面放苹果
消费者:从公共的盒子里面取苹果
盒子:盒子的容量不能超过5
下面我们用两者方法分别实现这样一个场景。
方法一: wait() 和 notify() 通信方法实现
看盒子代码
public class PublicBox
{
private int apple =
0;
public synchronized void increace()
{
while (apple ==5)
{
[align=left] try { [/align]
[align=left] wait(); [/align]
} catch (InterruptedException
e) {
[align=l
4000
eft] e.printStackTrace(); [/align]
[align=left] } [/align]
[align=left] [/align]
[align=left] } [/align]
[align=left] apple++; [/align]
[align=left] System. out .println("生成苹果成功!" );[/align]
[align=left] notify(); [/align]
[align=left] } [/align]
public synchronized void decreace()
{
while (apple ==0)
{
[align=left] try { [/align]
[align=left] wait(); [/align]
} catch (InterruptedException
e) {
[align=left] e.printStackTrace(); [/align]
[align=left] } [/align]
[align=left] } [/align]
[align=left] apple--; [/align]
[align=left] System. out.println( "消费苹果成功!" );[/align]
[align=left] notify(); [/align]
[align=left] } [/align]
[align=left] [/align]
public static void main(String
[]args)
[align=left] {[/align]
[align=left] PublicBox box= new PublicBox();[/align]
[align=left] [/align]
[align=left] Consumer con= new Consumer(box);[/align]
[align=left] Producer pro= new Producer(box);[/align]
[align=left] [/align]
[align=left] Thread t1= new Thread(con);[/align]
[align=left] Thread t2= new Thread(pro);[/align]
[align=left] [/align]
[align=left] t1.start();[/align]
[align=left] t2.start();[/align]
[align=left] [/align]
[align=left] [/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] [/align]
生产者代码(定义十次):
public class Producer implements Runnable
{
[align=left] private PublicBox box; [/align]
[align=left] [/align]
public Producer(PublicBox
box) {
this .box =
box;
[align=left] } [/align]
[align=left] [/align]
[align=left] @Override [/align]
public void run()
{
for( int i=0;i<10;i++)
[align=left] {[/align]
[align=left] try {[/align]
System. out .println("pro
i:" +i);
[align=left] Thread. sleep(30);[/align]
} catch (InterruptedException
e) {
// TODO:
handle exception
[align=left] e.printStackTrace();[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] box.increace(); [/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] } [/align]
[align=left]}[/align]
消费者代码(同样十次):
[align=left][/align]
public class Consumer implements Runnable
{
[align=left] private PublicBox box; [/align]
[align=left] [/align]
public Consumer(PublicBox
box) {
this .box =
box;
[align=left] } [/align]
[align=left] [/align]
[align=left] @Override [/align]
public void run()
{
[align=left] [/align]
[align=left] for( int i=0;i<10;i++)[/align]
[align=left] {[/align]
[align=left] try {[/align]
System. out .println("Con:
i " +i);
Thread. sleep(3000);
// 这里设置跟上面30不同是为了 盒子中的苹果能够增加,不会生产一个马上被消费
} catch (InterruptedException
e) {
// TODO:
handle exception
[align=left] e.printStackTrace();[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] box.decreace(); [/align]
[align=left] } [/align]
[align=left] } [/align]
[align=left]}[/align]
[align=left] [/align]
输出如下:
[align=left]pro i:0[/align]
[align=left]Con: i 0[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:1[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:2[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:3[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:4[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:5[/align]
[align=left]消费苹果成功![/align]
[align=left]Con: i 1[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:6[/align]
[align=left]消费苹果成功![/align]
[align=left]Con: i 2[/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:7[/align]
[align=left]消费苹果成功![/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:8[/align]
[align=left]Con: i 3[/align]
[align=left]消费苹果成功![/align]
[align=left]生成苹果成功![/align]
[align=left]pro i:9[/align]
[align=left]Con: i 4[/align]
[align=left]消费苹果成功![/align]
[align=left]生成苹果成功![/align]
[align=left]Con: i 5[/align]
[align=left]消费苹果成功![/align]
[align=left]Con: i 6[/align]
[align=left]消费苹果成功![/align]
[align=left]Con: i 7[/align]
[align=left]消费苹果成功![/align]
[align=left]Con: i 8[/align]
[align=left]消费苹果成功![/align]
[align=left]Con: i 9[/align]
[align=left]消费苹果成功![/align]
[align=left]
[/align]
方法二:采用阻塞队列实现生产者消费者模式
阻塞队列实现生产者消费者模式超级简单,它提供开箱即用支持阻塞的方法put()和take(),开发者不需要写困惑的wait-nofity代码去实现通信。BlockingQueue 一个接口,Java5提供了不同的现实,如ArrayBlockingQueue和LinkedBlockingQueue,两者都是先进先出(FIFO)顺序。而ArrayLinkedQueue是自然有界的,LinkedBlockingQueue可选的边界。下面这是一个完整的生产者消费者代码例子,对比传统的wait、nofity代码,它更易于理解。
盒子代码:
[align=left]import java.util.concurrent.BlockingQueue;[/align]
[align=left]import java.util.concurrent.LinkedBlockingQueue;[/align]
[align=left]
[/align]
public class PublicBoxQueue
{
[align=left]
[/align]
[align=left] [/align]
public static void main(String
[]args)
[align=left] {[/align]
BlockingQueue publicBoxQueue= new LinkedBlockingQueue(5);
//定义了一个大小为5的盒子
[align=left] [/align]
[align=left] Thread pro= new Thread(new ProducerQueue(publicBoxQueue));[/align]
[align=left] Thread con= new Thread(new ConsumerQueue(publicBoxQueue));[/align]
[align=left] [/align]
[align=left] pro.start();[/align]
[align=left] con.start();[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left]}[/align]
生产者:
[align=left]package dsd;[/align]
[align=left]
[/align]
[align=left]import java.util.concurrent.BlockingQueue;[/align]
[align=left]
[/align]
public class ProducerQueue implements Runnable
{
[align=left]
[/align]
[align=left] private final BlockingQueue proQueue;[/align]
[align=left] [/align]
[align=left] public ProducerQueue(BlockingQueue proQueue)[/align]
[align=left] {[/align]
[align=left] this .proQueue =proQueue;[/align]
[align=left] }[/align]
[align=left]
[/align]
[align=left] @Override[/align]
public void run()
{
// TODO Auto-generated
method stub
[align=left] [/align]
[align=left] for (int i=0;i<10;i++)[/align]
[align=left] {[/align]
[align=left] try {[/align]
System. out .println("生产者生产的苹果编号为
: " +i); //放入十个苹果编号 为1到10
[align=left] proQueue .put(i);[/align]
[align=left] [/align]
[align=left] /*Thread.sleep(3000);*/[/align]
} catch (InterruptedException
e) {
// TODO:
handle exception
[align=left] e.printStackTrace();[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] [/align]
[align=left]}[/align]
消费者:
[align=left]package dsd;[/align]
[align=left]
[/align]
[align=left]import java.util.concurrent.BlockingQueue;[/align]
[align=left]
[/align]
public class ConsumerQueue implements Runnable
{
[align=left]
[/align]
[align=left] private final BlockingQueue conQueue;[/align]
[align=left] [/align]
[align=left] public ConsumerQueue(BlockingQueue conQueue)[/align]
[align=left] {[/align]
[align=left] this .conQueue =conQueue;[/align]
[align=left] }[/align]
[align=left]
[/align]
[align=left] @Override[/align]
public void run()
{
// TODO Auto-generated
method stub
[align=left] for (int i=0;i<10;i++)[/align]
[align=left] {[/align]
[align=left] try {[/align]
System. out .println("消费者消费的苹果编号为
:" +conQueue .take());
[align=left] Thread. sleep(3000); //在这里sleep是为了看的更加清楚些[/align]
[align=left] [/align]
} catch (InterruptedException
e) {
// TODO:
handle exception
[align=left] e.printStackTrace();[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] [/align]
[align=left]}[/align]
[align=left]
[/align]
[align=left]结果如下:[/align]
[align=left]
[/align]
[align=left]生产者生产的苹果编号为 : 0[/align]
[align=left]生产者生产的苹果编号为 : 1[/align]
[align=left]消费者消费的苹果编号为 :0[/align]
[align=left]生产者生产的苹果编号为 : 2[/align]
[align=left]生产者生产的苹果编号为 : 3[/align]
[align=left]生产者生产的苹果编号为 : 4[/align]
[align=left]生产者生产的苹果编号为 : 5[/align]
[align=left]生产者生产的苹果编号为 : 6[/align]
[align=left]生产者生产的苹果编号为 : 7[/align]
[align=left]消费者消费的苹果编号为 :1[/align]
[align=left]消费者消费的苹果编号为 :2[/align]
[align=left]生产者生产的苹果编号为 : 8[/align]
[align=left]消费者消费的苹果编号为 :3[/align]
[align=left]生产者生产的苹果编号为 : 9[/align]
[align=left]消费者消费的苹果编号为 :4[/align]
[align=left]消费者消费的苹果编号为 :5[/align]
[align=left]消费者消费的苹果编号为 :6[/align]
[align=left]消费者消费的苹果编号为 :7[/align]
[align=left]消费者消费的苹果编号为 :8[/align]
[align=left]消费者消费的苹果编号为 :9[/align]
生产者消费者模式的好处
它的确是一种实用的设计模式,常用于编写多线程或并发代码。下面是它的一些优点:
它简化的开发,你可以独立地或并发的编写消费者和生产者,它仅仅只需知道共享对象是谁
生产者不需要知道谁是消费者或者有多少消费者,对消费者来说也是一样
生产者和消费者可以以不同的速度执行
分离的消费者和生产者在功能上能写出更简洁、可读、易维护的代码
转自http://blog.csdn.net/yujin753/article/details/45723175
相关文章推荐
- java 多线程并发系列之 生产者消费者模式的两种实现
- java 多线程并发系列之 生产者消费者模式的两种实现
- JAVA多线程-线程间通信(二)-生产者/消费者模式实现
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- java生产者/消费者模式实现——一生产者一消费者(操作值)
- Java生产者-消费者模式的阻塞队列实现
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- java 编码实现简单的生产者-消费者模式
- java 用多线程实现多生产者和多消费者模式
- java使用LinkedBlockingQueue实现 生产者 消费者模式
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- java消费者生产者模式及JDK之阻塞队列LinkedBlockingQueue实现
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- Java实现生产者/消费者模式
- JAVA并发实现五(生产者和消费者模式wait和notify方式实现)
- 设计模式-生产者与消费者Java实现
- JAVA 生产者消费者模式的实现
- 关于生产者与消费者模式的两种实现方式
- JAVA 阻塞队列实现 生产者和消费者 模式