Java 并发容器 -- BlockingQueue

BlockingQueue接口

Queue

常用方法

Throws exception Returns special value
Insert add offer
Remove remove poll
Examine element peek

Queue接口

package java.util

public interface Queue<E> extends Collection<E> {
    // 向队列尾部插入一个无素,如果是有界队列,此时队列已满,则抛出IllegalStateException异常
    boolean add(E e);
    // 同add方法的区别是:如果是有界队列,此时队列已满,则返回false
    boolean offer(E e);
    // 从队列的头部取出一个元素并删除该无素。如果队列是空,则抛出NoSuchElementException异常
    E remove();
    // 同remove方法的区别是:如果队列是空,则返回null
    E poll();
    // 从队列的头部获取一个元素但不删除该元素,如果队列是空,则抛出NoSuchElementException异常
    E element();
    // 同element方法的区别是:如果队列是空,则返回null
    E peek();
}

Deque

常用方法

  • First element (Head)
  • Last element (Tail)
Throws Exception Returns special value Throws Exception Returns special value
Insert addFirst offerFirst addLast offerLast
Remove removeFirst pollFirst removeLast pollLast
Examine getFirst peekFirst getLast peekLast

Deque与Queue

Queue和Deque的一些方法的功能是一样的。如下表:

Queue Method Equivalent Deque Method
add addLast
offer offerLast
remove removeFirst
poll pollFirst
element getFirst
peek peekFirst

Deque与Stack

Deque可以作为LIFO(Last-In-First-Out),和Stack一样。

Stack Method Equivalent Deque Method
push addFirst
pop removeFirst
peek peekFirst

Deque接口

public interface Deque<E> extends Queue<E> {
    // 向队列的头部插入一个元素。如果是有界队列,此时队列已满,则抛出IllegalStateException异常
    void addFirst(E e);
    // 向队列的尾部插入一个元素。如果是有界队列,此时队列已满,则抛出IllegalStateException异常
    void addLast(E e);
    // 向队列的头部插入一个元素。如果是有界队列,此时队列已满,则返回false
    boolean offerFirst(E e);
    // 向队列的尾部插入一个元素。如果是有界队列,此时队列已满,则返回false
    boolean offerLast(E e);
    // 从队列的头部取出一个元素并删除该无素。如果队列是空,则抛出NoSuchElementException异常
    E removeFirst();
    // 从队列的尾部取出一个元素并删除该无素。如果队列是空,则抛出NoSuchElementException异常
    E removeLast();
    // 从队列的头部取出一个元素并删除该无素。如果队列是空,则返回null
    E pollFirst();
    // 从队列的尾部取出一个元素并删除该无素。如果队列是空,则返回null
    E pollLast();
    // 从队列的头部获取一个元素但不删除该元素,如果队列是空,则抛出NoSuchElementException异常
    E getFirst();
    // 从队列的尾部获取一个元素但不删除该元素,如果队列是空,则抛出NoSuchElementException异常
    E getLast();
    // 从队列的头部获取一个元素但不删除该元素,如果队列是空,则返回null
    E peekFirst();
    // 从队列的尾部获取一个元素但不删除该元素,如果队列是空,则返回null
    E peekLast();
    // 删除队列第一次出现该元素。如果不存在则返回false
    boolean removeFirstOccurrence(Object o);
    // 删除队列最后一次出现该元素,如果不存在则返回false
    boolean removeLastOccurrence(Object o);

    // *** Queue methods ***
    
    // 同 addLast 方法一样
    boolean add(E e);
    // 同 offerLast 方法一样
    boolean offer(E e);
    // 同 removeFirst 方法一样
    E remove();
    // 同 pollFirst 方法一样
    E poll();
    // 同 getFirst 方法一样
    E element();
    // 同 peekFirst 方法一样
    E peek();


    // *** Stack methods ***
    
    // 同 addFirst 方法一样
    void push(E e);
    // 同 removeFirst 方法一样
    E pop();

    // *** Collection methods ***

    // 同 removeFirstOccurrence 方法一样
    boolean remove(Object o);
    // 队列中包含指定的元素时返回true(至少有一个), 否则返回false
    boolean contains(Object o);
    // 队列中的元素个数
    public int size();
    // 提供从 head -> tail 方式遍历队列元素
    Iterator<E> iterator();
    // 提供从 tail -> head 方法遍历队列元素
    Iterator<E> descendingIterator();

}

BlockingQueue

BlockingQueue是线程安全的阻塞队列。通常用于实现生产者-消费者的情形。

BlockingQueue新增支持阻塞的相关方法:

  • 当队列已满时:则不允许插入元素,此时方法处于阻塞状态,直到队列不为空时,才可以继续执行。
  • 当队队列为空时:则不允拿走元素,此时方法处于阻塞状态,直到队列中有元素时,才可以继续执行。

常用方法

Throws exception Returns special value Blocks Times out
Insert add offer put offer(long, TimeUnit)
Remove remove poll take poll(long, TimeUnit)
Examine element peek -- --

BlockingQueue接口

public interface BlockingQueue<E> extends Queue<E> {
    // 向队列尾部插入一个无素,如果是有界队列,此时队列已满,则抛出IllegalStateException异常
    boolean add(E e);
    // 向队列尾部插入一个无素,如果是有界队列,此时队列已满,则返回false
    boolean offer(E e);
    // 向队列尾部插入一个无素,如果是有界队列,此时队列已满,则调用此方法的线程处于阻塞状态。注意该方法支持被设置中断
    void put(E e) throws InterruptedException;
    // 向队列尾部插入一个无素,如果是有界队列,此时队列已满,则调用此方法的线程在指定的时间内处于阻塞状态。如果指定时间内不能插入元素则返回false。注意该方法支持被设置中断
    boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException;
    // 从队列的头部取出一个元素并删除该无素。如果队列是空,则调用些方法的线程处于阻塞状态。注意该方法支持被设置中断。
    E take() throws InterruptedException;
    // 从队列的头部取出一个元素并删除该元素,如果队列是空,则调用此方法的线程在指定的时间内处于阻塞状态。如果指定时间内不能获取到元素,则返回null。注意该方法支持被设置中断
    E poll(long timeout, TimeUnit unit)
        throws InterruptedException;
    // 返回队列中剩余的容量。注意,不能用该方法来判断队列是否已满或已空来决定是否插入或拿走操作。
    int remainingCapacity();
    // 从队列中删除指定的元素,如果不存在则返回false
    boolean remove(Object o);
    // 指定元素是否存在队列中
    public boolean contains(Object o);
    // 删除队列中所有元素并添加到Collection集合中。此方法比重复执行poll方法要更高效。
    int drainTo(Collection<? super E> c);
    // 删除队列中指定元素个数并添加到Collection集合中
    int drainTo(Collection<? super E> c, int maxElements);
}

TransferQueue

TransferQueue提供生产者可以等待(阻塞)消费者收到消息的相关功能。如生产者线程调用transfer方法时,必须等到消费者线程调用take方法或poll方法拿到消息时,生产者线程才可以继续往下处理,否则一直处于阻塞状态。

TransferQueue接口

public interface TransferQueue<E> extends BlockingQueue<E> {
    // 生产者线程尝试传输消息,如果有消费者线程调用take或poll方法时,该方法返回true,否则返回false。Non-blocking
    boolean tryTransfer(E e);
    // 生产者传输消息,如果有消费者线程调用take或poll方法,该方法直接返回;否则该线程处于阻塞状态
    void transfer(E e) throws InterruptedException;
    // 生产者线程在指定的时间内尝试传输消息,如果有消费者线程调用take或poll方法时,该方法返回true,如果超出指定时间内则返回false
    boolean tryTransfer(E e, long timeout, TimeUnit unit)
        throws InterruptedException;
    // 是否存在有等待获取消息的消费者
    boolean hasWaitingConsumer();
    // 正在等待获取消息的消费者的数量
    int getWaitingConsumerCount();
}

AbstractQueue

AbstractQueue是抽象类实现了部分Queue的方法,如add、remove、element方法;继承了AbstractCollection类,实现了clear、addAll方法。

AbstractQueue抽象类采用模板方法的设计模式.

public abstract class AbstractQueue<E>
    extends AbstractCollection<E>
    implements Queue<E> {
    
    protected AbstractQueue() {
    }
    
    public boolean add(E e) {
        // offer方法由子类实现,如果offer方法返回false,则抛IllegalStateException异常
        if (offer(e))
            return true;
        else
            throw new IllegalStateException("Queue full");
    }

    public E remove() {
        // poll方法由子类实现,如果poll方法返回null,则抛NoSuchElementException异常
        E x = poll();
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }

    public E element() {
        // peek方法由子类实现,如果peek方法返回null,则抛NoSuchElementException异常
        E x = peek();
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }

    public void clear() {
        // 轮徇调用poll方法删除队列中的元素
        while (poll() != null)
            ;
    }
}

小结

总结Queue、Deque、BlockingQueue和TransferQueue接口相关的方法的说明。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351