通过阻塞队列实现生产者消费者模型

生产者消费者模式是并发、多线程编程中经典的设计模式,生产者和消费者通过分离的执行工作解耦,简化了开发模式,生产者和消费者可以以不同的速度生产和消费数据。这篇文章我们来看看什么是生产者消费者模式,这个问题也是多线程面试题中经常被提及的。如何使用阻塞队列(Blocking Queue)解决生产者消费者模式,以及使用生产者消费者模式的好处。

真实世界中的生产者消费者模式

生产者和消费者模式在生活当中随处可见,它描述的是协调与协作的关系。比如一个人正在准备食物(生产者),而另一个人正在吃(消费者),他们使用一个共用的桌子用于放置盘子和取走盘子,生产者准备食物,如果桌子上已经满了就等待,消费者(那个吃的)等待如果桌子空了的话。这里桌子就是一个共享的对象。在Java Executor框架自身实现了生产者消费者模式它们分别负责添加和执行任务。

生产者消费者模式的好处

它的确是一种实用的设计模式,常用于编写多线程或并发代码。下面是它的一些优点:

  1.  它简化的开发,你可以独立地或并发的编写消费者和生产者,它仅仅只需知道共享对象是谁
  2. 生产者不需要知道谁是消费者或者有多少消费者,对消费者来说也是一样
  3.  生产者和消费者可以以不同的速度执行
  4.  分离的消费者和生产者在功能上能写出更简洁、可读、易维护的代码

多线程中的生产者消费者问题

生产者消费者问题是一个流行的面试题,面试官会要求你实现生产者消费者设计模式,以至于能让生产者应等待如果队列或篮子满了的话,消费者等待如果队列或者篮子是空的。这个问题可以用不同的方式来现实,经典的方法是使用wait和notify方法在生产者和消费者线程中合作,在队列满了或者队列是空的条件下阻塞,Java5的阻塞队列(BlockingQueue)数据结构更简单,因为它隐含的提供了这些控制,现在你不需要使用wait和nofity在生产者和消费者之间通信了,阻塞队列的put()方法将阻塞如果队列满了,队列take()方法将阻塞如果队列是空的。在下部分我们可以看到代码例子。

使用阻塞队列实现生产者消费者模式

阻塞队列实现生产者消费者模式超级简单,它提供开箱即用支持阻塞的方法put()和take(),开发者不需要写困惑的wait-nofity代码去实现通信。BlockingQueue 一个接口,Java5提供了不同的现实,如ArrayBlockingQueue和LinkedBlockingQueue,两者都是先进先出(FIFO)顺序。而ArrayLinkedQueue是自然有界的,LinkedBlockingQueue可选的边界。下面这是一个完整的生产者消费者代码例子,对比传统的wait、nofity代码,它更易于理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
 
public class ProducerConsumerPattern {
 
     public static void main(String args[]){
 
      //Creating shared object
      BlockingQueue sharedQueue = new LinkedBlockingQueue();
 
      //Creating Producer and Consumer Thread
      Thread prodThread = new Thread( new Producer(sharedQueue));
      Thread consThread = new Thread( new Consumer(sharedQueue));
 
      //Starting producer and Consumer thread
      prodThread.start();
      consThread.start();
     }
 
}
 
//Producer Class in java
class Producer implements Runnable {
 
     private final BlockingQueue sharedQueue;
 
     public Producer(BlockingQueue sharedQueue) {
         this .sharedQueue = sharedQueue;
     }
 
     @Override
     public void run() {
         for ( int i= 0 ; i< 10 ; i++){
             try {
                 System.out.println( "Produced: " + i);
                 sharedQueue.put(i);
             } catch (InterruptedException ex) {
                 Logger.getLogger(Producer. class .getName()).log(Level.SEVERE, null , ex);
             }
         }
     }
 
}
 
//Consumer Class in Java
class Consumer implements Runnable{
 
     private final BlockingQueue sharedQueue;
 
     public Consumer (BlockingQueue sharedQueue) {
         this .sharedQueue = sharedQueue;
     }
 
     @Override
     public void run() {
         while ( true ){
             try {
                 System.out.println( "Consumed: " + sharedQueue.take());
             } catch (InterruptedException ex) {
                 Logger.getLogger(Consumer. class .getName()).log(Level.SEVERE, null , ex);
             }
         }
     }
 
}
 
Output:
Produced: 0
Produced: 1
Consumed: 0
Produced: 2
Consumed: 1
Produced: 3
Consumed: 2
Produced: 4
Consumed: 3
Produced: 5
Consumed: 4
Produced: 6
Consumed: 5
Produced: 7
Consumed: 6
Produced: 8
Consumed: 7
Produced: 9
Consumed: 8
Consumed: 9


方法二


final class BackgroundTask implements Runnable {


    private final PendingPostQueue queue;
    private final EventBus eventBus;


    private volatile boolean executorRunning;


    BackgroundPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }


    public void enqueue(int i) {

        PendingPost pendingPost = PendingPost.obtainPendingPost(i);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!executorRunning) {
                executorRunning = true;
                eventBus.getExecutorService().execute(this);
            }
        }
    }


    @Override
    public void run() {
        try {
            try {
                while (true) {
                    PendingPost pendingPost = queue.poll(1000);
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                   System.out.println("i=%d",i);
                }
            } catch (InterruptedException e) {
                Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }


}

public class Test {
 
     public static void main(String args[]){
  private final ExecutorService executorService = Executors.singleThreadtool();

BackgroundTask task = new BackgroundTask(executorService);
 
for (int i = 0 ; i < 10; i++){
task.enqueue(i);
}
     
 
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值