使用阻塞隊列解決生產者-消費者問題

若是你想避免使用錯綜複雜的waitnotify的語句,BlockingQueue很是有用。BlockingQueue可用於解決生產者-消費者問題,以下代碼示例。對於每一個開發人員來講,生產者消費者問題已經很是熟悉了,這裏我將不作詳細描述。java

爲何BlockingQueue適合解決生產者消費者問題

任何有效的生產者-消費者問題解決方案都是經過控制生產者put()方法(生產資源)和消費者take()方法(消費資源)的調用來實現的,一旦你實現了對方法的阻塞控制,那麼你將解決該問題。安全

Java經過BlockingQueue提供了開箱即用的支持來控制這些方法的調用(一個線程建立資源,另外一個消費資源)。java.util.concurrent包下的BlockingQueue接口是一個線程安全的可用於存取對象的隊列。數據結構

BlockingQueue是一種數據結構,支持一個線程往裏存資源,另外一個線程從裏取資源。這正是解決生產者消費者問題所須要的,那麼讓咱們開始解決該問題吧。測試

使用BlockingQueue解決生產者消費者問題

生產者

如下代碼用於生產者線程this

package cn.edu.hdu.chenpi.cpdemo.howtodoinjava;

import java.util.concurrent.BlockingQueue;

class Producer implements Runnable {
    protected BlockingQueue<Object> queue;

    Producer(BlockingQueue<Object> theQueue) {
        this.queue = theQueue;
    }

    public void run() {
        try {
            while (true) {
                Object justProduced = getResource();
                queue.put(justProduced);
                System.out.println("Produced resource - Queue size now = "
                        + queue.size());
            }
        } catch (InterruptedException ex) {
            System.out.println("Producer INTERRUPTED");
        }
    }

    Object getResource() {
        try {
            Thread.sleep(100); // simulate time passing during read
        } catch (InterruptedException ex) {
            System.out.println("Producer Read INTERRUPTED");
        }
        return new Object();
    }
}

這裏,生產者線程建立一個資源(Object對象)並將它存入隊列中,若是隊列已經滿了(最大爲20),它將會等待直到消費者線程從隊列中取走資源,因此隊列的長度永遠不會超過最大值,好比20。spa

消費者

如下代碼用於消費者線程線程

package cn.edu.hdu.chenpi.cpdemo.howtodoinjava;

import java.util.concurrent.BlockingQueue;

class Consumer implements Runnable {
    protected BlockingQueue<Object> queue;

    Consumer(BlockingQueue<Object> theQueue) {
        this.queue = theQueue;
    }

    public void run() {
        try {
            while (true) {
                Object obj = queue.take();
                System.out.println("Consumed resource - Queue size now = "
                        + queue.size());
                take(obj);
            }
        } catch (InterruptedException ex) {
            System.out.println("CONSUMER INTERRUPTED");
        }
    }

    void take(Object obj) {
        try {
            Thread.sleep(100); // simulate time passing
        } catch (InterruptedException ex) {
            System.out.println("Consumer Read INTERRUPTED");
        }
        System.out.println("Consuming object " + obj);
    }
}

隊列中有資源的話,消費者線程將從隊列中取走資源,不然會等待直到生產者建立資源。3d

測試該解決方案是否運行正常

如今,讓咱們測試下以上生產者消費者線程是否能正常工做:code

package cn.edu.hdu.chenpi.cpdemo.howtodoinjava;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class ProducerConsumerExample {
    public static void main(String[] args) throws InterruptedException {
        int numProducers = 4;
        int numConsumers = 3;

        BlockingQueue<Object> myQueue = new LinkedBlockingQueue<>(20);

        for (int i = 0; i < numProducers; i++) {
            new Thread(new Producer(myQueue)).start();
        }

        for (int i = 0; i < numConsumers; i++) {
            new Thread(new Consumer(myQueue)).start();
        }

        // Let the simulation run for, say, 10 seconds
        Thread.sleep(10 * 1000);

        // End of simulation - shut down gracefully
        System.exit(0);
    }
}

當咱們運行以上代碼,會發現相似以下輸出結果:對象

Consumed resource - Queue size now = 1
Produced resource - Queue size now = 1
Consumed resource - Queue size now = 1
Consumed resource - Queue size now = 1
Produced resource - Queue size now = 1
Produced resource - Queue size now = 1
Produced resource - Queue size now = 1
Consuming object java.lang.Object@14c7f728
Consumed resource - Queue size now = 0
Consuming object java.lang.Object@2b71e323
Consumed resource - Queue size now = 0
Produced resource - Queue size now = 0
Produced resource - Queue size now = 1
Produced resource - Queue size now = 2
Consuming object java.lang.Object@206dc00b
Consumed resource - Queue size now = 1
Produced resource - Queue size now = 2
Produced resource - Queue size now = 3
Consuming object java.lang.Object@1a000bc0
Consumed resource - Queue size now = 2
Consuming object java.lang.Object@25b6183d
Consumed resource - Queue size now = 1
Produced resource - Queue size now = 2
Produced resource - Queue size now = 3
...
...
Produced resource - Queue size now = 20
Consuming object java.lang.Object@2b3cd3a6
Consumed resource - Queue size now = 19
Produced resource - Queue size now = 20
Consuming object java.lang.Object@3876982d
Consumed resource - Queue size now = 19
Produced resource - Queue size now = 20

從輸出結果中,咱們能夠發現隊列大小永遠不會超過20,消費者線程消費了生產者生產的資源。

 

譯文連接:http://howtodoinjava.com/algorithm/producer-consumer-problem-using-blockingqueue/

相關文章
相關標籤/搜索