您的位置:首页 > 编程语言 > Java开发

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()

       
        forint 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]        forint 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐