Pratice Of Concurrency(一: BlockingQueue )

Java java.util.currency包中的BlockingQueue接口意味着線程能夠在一個隊列中添加和提取對象.在接下來的段落中,咱們將學習如何使用BlockingQueue接口.html

BlockingQueue的使用

BlockingQueue典型應用是用於一個線程生產對象,另外一個線程消費對象.java

下面是一個原理描述圖:併發

一個阻塞隊列伴隨着一個線程往隊列中添加對象,另外一個線程從隊列中提取對象.ide

生產線程負責生產新對象併發它添加進隊列中,直到達到隊列所能容納的邊界值爲止.即達到容量限制.若是隊列達到容量限制,則生產線程在插入新對象時將會發生阻塞.直到有一個消費線程從隊列中取走一個對象爲止.學習

消費線程負責從阻塞隊列中取出對象並處理它們.若是消費線程嘗試從空隊列中取出空隊列,那麼消費線程將會阻塞直到生產線程往隊列中放入一個對象爲止.this

BlockingQueue方法

一個阻塞隊列包含四種大相徑庭的方法集,用於完成在隊列中插入,移除和檢查元素.每種集合的不一樣之處在於操做請求不能被當即執行時的不一樣行爲.下面是這些方法的列表:spa

Throws Exception Special Value Blocks Times Out
Insert add(o) offer(o) put(o) offer(o, timeout, time unit)
Remove remove(o) poll() take() poll(timeout, timeunit)
Examine element() peek()

四種不一樣的行爲結合以下:線程

  1. Throws Exception: 當嘗試操做不能被當即執行時, 將拋出一個異常
  2. Special Value: 當嘗試操做不能被當即執行時, 指定一個返回值(一般爲 true / false)
  3. Blocks: 當嘗試操做不能被當即執行時, 阻塞方法調用直到可以執行成功爲止
  4. Time Out: 當嘗試操做不能被當即執行時, 阻塞方法調用直到可以執行成功爲止, 但等待不能超過指定的超時時長.若超出時長, 不管成功或失敗返回一個指定的值.(典型的例子是 true / false)

不能插入null到BlockingQueue中.若是你這麼作了,BlockingQueue將拋出一個NullPointerException.code

固然咱們也可以訪問BlockingQueue的全部元素, 不僅是隊頭和隊尾. 例如, 你須要出隊一個對象用於執行,但你的應用決定取消它.那麼你仍然可使用相似remove(o)方法來移除隊列中指定的對象.然而這不是很高效,因此你不該該使用這類方法, 除非你真的須要這麼作.cdn

BlockingQueue的多種實現

BlockingQueue只是一個接口, 因此你須要使用它衆多實現的其中一種來使用它.java.util.concurrency包中有以下幾種BlockingQueue的接口實現(在Java6中):

  • ArrayBlockingQueue
  • DelayQueue
  • LinkedBlockingQueue
  • PriorityBlockingQueue
  • SynchronousQueue

Java BlockingQueue實例

下面是一個Java BlockingQueue的實例. 實例中使用BlockingQueue接口的實現類,ArrayBlockingQueue.

首先,BlockingQueueExample類中分別啓動一個生產和消費線程.生產線程負責插入字符串到共享BlockingQueue中,而消費線程則負責取走它們.

public class ArrayBlockingQueueExample {
    public static void main(String[] args) {
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1024);
        Producer producer = new Producer(queue);
        Consumer consumer = new Consumer(queue);

        new Thread(producer).start();
        new Thread(consumer).start();

        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
複製代碼

下面是Producer類.注意咱們每調用一次put()就會讓線程睡眠一秒.這會致使消費線程在隊列中等待對象時發生阻塞.

public class Producer implements Runnable {
    private ArrayBlockingQueue<String> queue;

    public Producer(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            queue.put("1");
            Thread.sleep(1000);
            queue.put("2");
            Thread.sleep(1000);
            queue.put("3");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
複製代碼

下面是Consumer類.它只是負責從隊列中取出字符串並經過System.out打印出來.

package org.menfre;

import java.util.concurrent.ArrayBlockingQueue;

public class Consumer implements Runnable {
    private ArrayBlockingQueue<String> queue;

    public Consumer(ArrayBlockingQueue<String> queue){
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            System.out.println(queue.take());
            System.out.println(queue.take());
            System.out.println(queue.take());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
複製代碼

該系列博文爲筆者複習基礎所著譯文或理解後的產物,複習原文來自Jakob Jenkov所著Java.util.concurrent

Next: ArrayBlockingQueue

相關文章
相關標籤/搜索