當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Java BlockingQueue用法及代碼示例


BlockingQueue接口Java 中的 與各種其他並發實用程序類一起添加到 Java 1.5 中,例如ConcurrentHashMap,計數信號量,CopyOnWriteArrrayLisBlockingQueue 接口通過在 BlockingQueue 已滿或為空時引入阻塞來支持流量控製(除了隊列之外)。嘗試將元素加入已滿隊列的線程會被阻塞,直到其他線程通過使一個或多個元素出列或完全清除隊列來在隊列中騰出空間。類似地,它會阻塞嘗試從空隊列中刪除的線程,直到其他線程插入項目為止。 BlockingQueue 不接受空值。如果我們嘗試將空項放入隊列,則會拋出異常NullPointerException.
Java 提供了多種 BlockingQueue 實現,例如LinkedBlockingQueue,ArrayBlockingQueue,PriorityBlockingQueue,SynchronousQueue等。Java BlockingQueue 接口實現是線程安全的。 BlockingQueue 的所有方法本質上都是原子的,並使用內部鎖或其他形式的並發控製。 Java 5 附帶了 BlockingQueue 實現java.util.concurrent包

BlockingQueue的用法

Usage of BlockingQueue 

由生產者 (put) 線程和消費者 (take) 線程訪問的 BlockingQueue

BlockingQueue的層次結構

Hierarchy of BlockingQueue

聲明

public interface BlockingQueue<E> extends Queue<E>

這裏,E是Collection中存儲的元素的類型。

實現 BlockingQueue 的類

我們無法直接提供 BlockingQueue 的實例,因為它是一個接口,因此要利用 BlockingQueue 的函數,我們需要使用實現它的類。另外,要在代碼中使用 BlockingQueue,請使用此 import 語句。

import java.util.concurrent.BlockingQueue;
                    (or)
import java.util.concurrent.*;

BlockingDeque的實現類是LinkedBlockingDeque。該類是BlockingDeque和鏈表數據結構的實現。 LinkedBlockingDeque 可以選擇使用構造函數進行限製,但是,如果未指定容量,則默認情況下它是 Integer.MAX_VALUE。節點在插入時動態添加,遵守容量限製。

創建對象的語法:

BlockingQueue<?> objectName = new LinkedBlockingDeque<?>();   
                         (or)
LinkedBlockingDeque<?> objectName = new LinkedBlockingDeque<?>();

示例:在下麵給出的代碼中,我們對 LinkedBlockingDeque 執行一些基本操作,例如創建對象、添加元素、刪除元素以及使用迭代器遍曆 LinkedBlockingDeque。

BlockingQueue Types

BlockingQueue 有兩種類型:

1.無界隊列:阻塞隊列的容量將設置為Integer.MAX_VALUE。在無界阻塞隊列的情況下,隊列永遠不會阻塞,因為它可能會增長到非常大的大小。當你添加元素時,它的大小會增加。

用法:

BlockingQueue blockingQueue = new LinkedBlockingDeque();

2.有界隊列:第二種隊列是有界隊列。對於有界隊列,您可以創建一個在隊列構造函數中傳遞隊列容量的隊列:

用法:

// Creates a Blocking Queue with capacity 5
BlockingQueue blockingQueue = new LinkedBlockingDeque(5);

使用 BlockingQueue 實現有界信號量

Java


// Java program that explains the internal
// implementation of BlockingQueue
import java.io.*;
import java.util.*;
class BlockingQueue<E> {
    // BlockingQueue using LinkedList structure
    // with a constraint on capacity
    private List<E> queue = new LinkedList<E>();
    // limit variable to define capacity
    private int limit = 10;
    // constructor of BlockingQueue
    public BlockingQueue(int limit) { this.limit = limit; }
    // enqueue method that throws Exception
    // when you try to insert after the limit
    public synchronized void enqueue(E item)
        throws InterruptedException
    {
        while (this.queue.size() == this.limit) {
            wait();
        }
        if (this.queue.size() == 0) {
            notifyAll();
        }
        this.queue.add(item);
    }
    // dequeue methods that throws Exception
    // when you try to remove element from an
    // empty queue
    public synchronized E dequeue()
        throws InterruptedException
    {
        while (this.queue.size() == 0) {
            wait();
        }
        if (this.queue.size() == this.limit) {
            notifyAll();
        }
        return this.queue.remove(0);
    }
   
    public static void main(String []args)
    {
    }
}



例子:

Java


// Java Program to demonstrate usage of BlockingQueue
import java.util.concurrent.*;
import java.util.*;
public class GFG {
    public static void main(String[] args)
        throws InterruptedException
    {
        // define capacity of ArrayBlockingQueue
        int capacity = 5;
        // create object of ArrayBlockingQueue
        BlockingQueue<String> queue
            = new ArrayBlockingQueue<String>(capacity);
        // Add elements to ArrayBlockingQueue using put
        // method
        queue.put("StarWars");
        queue.put("SuperMan");
        queue.put("Flash");
        queue.put("BatMan");
        queue.put("Avengers");
        // print Queue
        System.out.println("queue contains " + queue);
        // remove some elements
        queue.remove();
        queue.remove();
        // Add elements to ArrayBlockingQueue
        // using put method
        queue.put("CaptainAmerica");
        queue.put("Thor");
        System.out.println("queue contains " + queue);
    }
}
輸出:
queue contains [StarWars, SuperMan, Flash, BatMan, Avengers]
queue contains [Flash, BatMan, Avengers, CaptainAmerica, Thor]

Basic Operations

1. 添加元素

根據我們嘗試使用的結構類型,可以以不同的方式將元素添加到 LinkedBlockedDeque 中。最常見的方法是add()方法,使用它我們可以在雙端隊列的末尾添加元素。我們還可以使用addAll()方法(這是Collection接口的一個方法)將整個集合添加到LinkedBlockingDeque中。如果我們希望將雙端隊列用作隊列,我們可以使用add()和put()。

Java


// Java Program Demonstrate add()
// method of BlockingQueue
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.*;
public class GFG {
   
    public static void main(String[] args)
        throws IllegalStateException
    {
        // create object of BlockingQueue
        BlockingQueue<Integer> BQ
            = new LinkedBlockingDeque<Integer>();
        // Add numbers to the BlockingQueue
        BQ.add(7855642);
        BQ.add(35658786);
        BQ.add(5278367);
        BQ.add(74381793);
        // before removing print BlockingQueue
        System.out.println("Blocking Queue: " + BQ);
    }
}
輸出
Blocking Queue: [7855642, 35658786, 5278367, 74381793]

2. 訪問元素

可以使用contains()、element()、peek()、poll() 訪問LinkedBlockingDeque 的元素。這些方法也有多種變體,上表中給出了它們及其說明。

Java


// Java Program for Accessing the elements of a
// LinkedBlockingDeque
import java.util.concurrent.*;
public class AccessingElements {
    public static void main(String[] args)
    {
        // Instantiate an object of LinkedBlockingDeque
        // named lbdq
        BlockingQueue<Integer> lbdq
            = new LinkedBlockingDeque<Integer>();
        // Add elements using add()
        lbdq.add(22);
        lbdq.add(125);
        lbdq.add(723);
        lbdq.add(172);
        lbdq.add(100);
        // Print the elements of lbdq on the console
        System.out.println(
            "The LinkedBlockingDeque, lbdq contains:");
        System.out.println(lbdq);
        // To check if the deque contains 22
        if (lbdq.contains(22))
            System.out.println(
                "The LinkedBlockingDeque, lbdq contains 22");
        else
            System.out.println("No such element exists");
        // Using element() to retrieve the head of the deque
        int head = lbdq.element();
        System.out.println("The head of lbdq: " + head);
    }
}


輸出
The LinkedBlockingDeque, lbdq contains:
[22, 125, 723, 172, 100]
The LinkedBlockingDeque, lbdq contains 22
The head of lbdq: 22

3. 刪除元素

可以使用remove()從LinkedBlockingDeque中刪除元素。其他方法如take()和poll()也可以用於刪除第一個和最後一個元素。

Java


// Java Program for removing elements from a
// LinkedBlockingDeque
import java.util.concurrent.*;
public class RemovingElements {
    public static void main(String[] args)
    {
        // Instantiate an object of LinkedBlockingDeque
        // named lbdq
        BlockingQueue<Integer> lbdq
            = new LinkedBlockingDeque<Integer>();
        // Add elements using add()
        lbdq.add(75);
        lbdq.add(86);
        lbdq.add(13);
        lbdq.add(44);
        lbdq.add(10);
        // Print the elements of lbdq on the console
        System.out.println(
            "The LinkedBlockingDeque, lbdq contains:");
        System.out.println(lbdq);
        // Remove elements using remove();
        lbdq.remove(86);
        lbdq.remove(44);
        // Trying to remove an element
        // that doesn't exist
        // in the LinkedBlockingDeque
        lbdq.remove(1);
        // Print the elements of lbdq on the console
        System.out.println(
            "\nThe LinkedBlockingDeque, lbdq contains:");
        System.out.println(lbdq);
    }
}
輸出
The LinkedBlockingDeque, lbdq contains:
[75, 86, 13, 44, 10]

The LinkedBlockingDeque, lbdq contains:
[75, 13, 10]

4. 迭代元素

要迭代 LinkedBlockingDeque 的元素,我們可以創建一個迭代器並使用 Iterable 接口(Java 集合框架的根)的方法來訪問元素。 Iterable 的 next() 方法返回任何集合的元素。

Java


// Java Program to iterate 
// through the LinkedBlockingDeque
import java.util.Iterator;
import java.util.concurrent.*;
public class IteratingThroughElements {
    public static void main(String[] args) {
         
        // Instantiate an object of LinkedBlockingDeque named lbdq
        BlockingQueue<Integer> lbdq = new LinkedBlockingDeque<Integer>();
         
        // Add elements using add()
        lbdq.add(166);
        lbdq.add(246);
        lbdq.add(66);
        lbdq.add(292);
        lbdq.add(98);
         
        // Create an iterator to traverse lbdq
        Iterator<Integer> lbdqIter = lbdq.iterator();
         
        // Print the elements of lbdq on to the console
        System.out.println("The LinkedBlockingDeque, lbdq contains:");
         
        for(int i = 0; i<lbdq.size(); i++)
        {
            System.out.print(lbdqIter.next() + " ");
        }        
    }
}
輸出
The LinkedBlockingDeque, lbdq contains:
166 246 66 292 98 

BlockingQueue的方法

METHOD

DESCRIPTION

add(E e) 如果可以在不違反容量限製的情況下立即將指定元素插入此隊列,則成功時返回 true,如果當前沒有可用空間,則拋出 IllegalStateException。
contains(Object o) 如果此隊列包含指定元素,則返回 true。
dropTo(Collection<? super E> c) 從此隊列中刪除所有可用元素並將它們添加到給定集合中。
dropTo(Collection<? super E> c, int maxElements) 從此隊列中刪除最多給定數量的可用元素並將它們添加到給定的集合中。
offer(E e) 如果可以在不違反容量限製的情況下立即執行此操作,則將指定元素插入此隊列,成功時返回 true,如果當前沒有可用空間則返回 false。
offer(E e, long timeout, TimeUnit unit) 將指定的元素插入此隊列中,如果需要空間可用,則等待指定的等待時間。
poll(long timeout, TimeUnit unit) 檢索並刪除此隊列的頭部,如果需要元素變得可用,則等待指定的等待時間。
put(E e) 將指定的元素插入此隊列,必要時等待空間可用。
remainingCapacity() 返回此隊列理想情況下(在沒有內存或資源限製的情況下)可以無阻塞地接受的附加元素的數量,如果沒有內在限製,則返回 Integer.MAX_VALUE。
remove(Object o) 從此隊列中刪除指定元素的單個實例(如果存在)。
take() 檢索並刪除此隊列的頭部,如有必要,則等待直到有元素可用。

接口 java.util.Collection 中聲明的方法

METHOD

DESCRIPTION

addAll(集合 <? 擴展 E> c) 將指定集合中的所有元素添加到此集合中(可選操作)。
clear() 從此集合中刪除所有元素(可選操作)。
containsAll(集合<?> c) 如果此集合包含指定集合中的所有元素,則返回 true。
equals(Object o) 比較指定對象與此集合是否相等。
hashCode() 返回此集合的哈希碼值。
isEmpty() 如果此集合不包含任何元素,則返回 true。
iterator() 返回此集合中元素的迭代器。
parallelStream() 返回一個可能並行的 Stream 並以此集合作為其源。
移除全部(集合<?> c) 刪除指定集合中也包含的所有該集合的元素(可選操作)。
removeIf(Predicate<? super E> 過濾器) 刪除此集合中滿足給定謂詞的所有元素。
keepAll(集合<?> c) 僅保留此集合中包含在指定集合中的元素(可選操作)。
size() 返回此集合中的元素數量。
spliterator() 在此集合中的元素上創建Spliterator
stream() 返回以此集合作為源的順序 Stream。
toArray() 返回一個包含此集合中所有元素的數組。
toArray(IntFunction<T[]> 生成器) 返回一個包含此集合中所有元素的數組,使用提供的生成器函數分配返回的數組。
toArray(T[] a) 返回一個包含該集合中所有元素的數組;返回數組的運行時類型是指定數組的運行時類型。

接口 java.lang.Iterable 中聲明的方法

METHOD

DESCRIPTION

Iterable forEach() 對 Iterable 的每個元素執行給定的操作,直到處理完所有元素或該操作引發異常。

接口 java.util.Queue 中聲明的方法

METHOD

DESCRIPTION

Queue element() 檢索但不刪除此隊列的頭部。
Queue peek() 檢索但不刪除此隊列的頭部,如果此隊列為空,則返回 null。
Queue poll() 檢索並刪除此隊列的頭部,如果此隊列為空,則返回 null。
BlockingQueue 檢索並刪除此隊列的頭部。

BlockingQueue 方法的行為

以下是 BlockingQueue 提供的用於對隊列進行插入、刪除和檢查操作的方法。如果未立即滿足請求的操作,四組方法中的每組方法的行為都會有所不同。

  • 拋出異常:如果請求的操作未立即滿足,則會拋出異常。
  • 特別值:如果操作沒有立即滿足,則返回一個特殊值。
  • Blocks:如果嘗試的操作未立即滿足,則方法調用將被阻止,並等待直到執行。
  • 超時:返回一個特殊值,告訴操作是否成功。如果請求的操作無法立即執行,則該方法調用會阻塞,直到可以執行為止,但等待的時間不會超過給定的超時時間。
操作 拋出異常 特別值 積木 超時
插入 BlockingQueue add() BlockingQueue offer() 把(e) BlockingQueue offer()
Remove BlockingQueue remove() BlockingQueue poll() BlockingQueue take() BlockingQueue poll()
檢查 element() peek() 不適用 不適用

參考:https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/BlockingQueue.html



相關用法


注:本文由純淨天空篩選整理自Rajput-Ji大神的英文原創作品 BlockingQueue Interface in Java。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。