java阻塞隊列實現生產者消費者模式

    生產者消費者模式是併發、多線程編程中經典的設計模式,生產者和消費者經過分離的執行工做解耦,簡化了開發模式,生產者和消費者能夠以不一樣的速度生產和消費數據。這篇文章咱們來看看什麼是生產者消費者模式,這個問題也是多線程面試題中常常被說起的。如何使用阻塞隊列(Blocking Queue)解決生產者消費者模式,以及使用生產者消費者模式的好處。java

    真實世界中的生產者消費者模式面試

    生產者和消費者模式在生活當中隨處可見,它描述的是協調與協做的關係。好比一我的正在準備食物(生產者),而另外一我的正在吃(消費者),他們使用一個共用的桌子用於放置盤子和取走盤子,生產者準備食物,若是桌子上已經滿了就等待,消費者(那個吃的)等待若是桌子空了的話。這裏桌子就是一個共享的對象。在Java Executor框架自身實現了生產者消費者模式它們分別負責添加和執行任務。編程

    生產者消費者模式的好處設計模式

    它的確是一種實用的設計模式,經常使用於編寫多線程或併發代碼。下面是它的一些優勢:數據結構

  1. 它簡化的開發,你能夠獨立地或併發的編寫消費者和生產者,它僅僅只需知道共享對象是誰多線程

  2. 生產者不須要知道誰是消費者或者有多少消費者,對消費者來講也是同樣併發

  3. 生產者和消費者能夠以不一樣的速度執行框架

  4. 分離的消費者和生產者在功能上能寫出更簡潔、可讀、易維護的代碼ide

    多線程中的生產者消費者問題this

    生產者消費者問題是一個流行的面試題,面試官會要求你實現生產者消費者設計模式,以致於能讓生產者應等待若是隊列或籃子滿了的話,消費者等待若是隊列或者籃子是空的。這個問題能夠用不一樣的方式來現實,經典的方法是使用wait和notify方法在生產者和消費者線程中合做,在隊列滿了或者隊列是空的條件下阻塞,Java5的阻塞隊列(BlockingQueue)數據結構更簡單,由於它隱含的提供了這些控制,如今你不須要使用wait和nofity在生產者和消費者之間通訊了,阻塞隊列的put()方法將阻塞若是隊列滿了,隊列take()方法將阻塞若是隊列是空的。在下部分咱們能夠看到代碼例子。

    使用阻塞隊列實現生產者消費者模式

    阻塞隊列實現生產者消費者模式超級簡單,它提供開箱即用支持阻塞的方法put()和take(),開發者不須要寫困惑的wait-nofity代碼去實現通訊。BlockingQueue 一個接口,Java5提供了不一樣的現實,如ArrayBlockingQueue和LinkedBlockingQueue,二者都是先進先出(FIFO)順序。而ArrayLinkedQueue是天然有界的,LinkedBlockingQueue可選的邊界。下面這是一個完整的生產者消費者代碼例子,對比傳統的wait、nofity代碼,它更易於理解。

    

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

    你能夠看到生產者線程生產數和消費者線程消費它以FIFO的順序,由於阻塞隊列只容許元素以FIFO的方式來訪問。以上就是使用阻塞隊列解決生產者消費者問題的所有,我確信它比wait/notify更簡單,但你要二者都準備若是你是去面試話。

相關文章
相關標籤/搜索