阻塞队列(BlockingQueue)方法介绍

简介

队列是一种先进先出(FIFO)的数据结构,阻塞队列在基本操作的基础上支持插入阻塞(队列已满)和移除阻塞(队列为空)。

阻塞队列元素不能为null,因为null值会作为队列为空时 poll和peek接口的返回值 。并且应该设置边界,如果没有指定容量大小,默认容量是Integer.MAX_VALUE

java中使用接口 BlockingQueue来表示阻塞队列,它具有众多的实现类,juc包下的主要有以下实现类

  • ArrayBlockingQueue : 基于数组的有界阻塞队列
  • LinkedBlockingQueue: 基于链表的有界(无参实例默认大小为:Integer.MAX_VALUE,也可以说是无界队列 )阻塞队列
  • PriorityBlockingQueue: 支持优先级排序的无界阻塞队列
  • SynchronousQueue: 不存储元素的阻塞队列
  • DelayQueue
操作方法

阻塞队列中提供的方法可以分为四类:

  • 抛出异常
  • 立即返回特定的值(null /false)
  • 阻塞当前线程
  • 阻塞指定的时间
一、插入元素

BlockingQueue 提供了以下方法往队列中添加元素 add、offer、put。
注意:

  1. 不能往队列中添加null元素
  2. 元素添加到队列尾部(追加)。
add
 /**
     * Inserts the specified element into this queue if it is possible to do
     * so immediately without violating capacity restrictions, returning
     * {@code true} upon success and throwing an
     * {@code IllegalStateException} if no space is currently available.
     * When using a capacity-restricted queue, it is generally preferable to
     * use {@link #offer(Object) offer}.
     *
     * @param e the element to add
     * @return {@code true} (as specified by {@link Collection#add})
     * @throws IllegalStateException if the element cannot be added at this
     *         time due to capacity restrictions
     * @throws ClassCastException if the class of the specified element
     *         prevents it from being added to this queue
     * @throws NullPointerException if the specified element is null
     * @throws IllegalArgumentException if some property of the specified
     *         element prevents it from being added to this queue
     */
    boolean add(E e);

向队列中添加一个元素,添加成功返回true,失败(队列已满)抛出异常IllegalStateException。对于有界队列最好使用offer方法。
添加元素不能为null

public static void main(String[] args) {
		// 容量为1的阻塞队列
        BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<String>(1);
        new Thread(()->{
            try {
                while(true){
                    Thread.sleep(1000);
                    System.out.println(blockingQueue.take());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        for(int i=0;i<3;i++){
            //使用add 方法
            boolean insertResult = blockingQueue.add("string... "+i);
            System.out.println("insert result ......  "+insertResult);
        }

    }

Exception in thread “main” java.lang.IllegalStateException: Queue full
insert result … true
at java.util.AbstractQueue.add(AbstractQueue.java:98)
at java.util.concurrent.ArrayBlockingQueue.add(ArrayBlockingQueue.java:312)
at thread.BlaockingQueueDemo.main(BlaockingQueueDemo.java:24)
string… 0

offer

offer方法是重载方法,有两种方式添加元素。

    boolean offer(E e);

向队列中添加一个元素,添加成功返回true,添加失败返回false。

    boolean offer(E e, long timeout, TimeUnit unit)

指定超时时间 ,在指定时间内插入元素返回true,否则返回false 。在等待过程中如果线程被中断(调用interrupt)会抛出InterruptedException

 public static void main(String[] args) {
        BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<String>(1);
        new Thread(()->{
            try {
                while(true){
                    Thread.sleep(1000);
                    blockingQueue.take();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        for(int i=0;i<3;i++){
            boolean insertResult = blockingQueue.offer("string... "+i);
            System.out.println("insert result ......  "+insertResult);
        }

    }

insert result … true
insert result … false
insert result … false

    public static void main(String[] args) {
        ArrayBlockingQueue<String> blockingQueue=new ArrayBlockingQueue<String>(1);
        new Thread(()->{
            try {
                while(true){
                    Thread.sleep(1000);
                    Object object =blockingQueue.take();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        Thread mainThread = Thread.currentThread();

        for(int i=0;i<3;i++){
            boolean insertResult = false;
            try {
                //中断主线程
                mainThread.interrupt();
                boolean insetResult = blockingQueue.offer("A",500,TimeUnit.MILLISECONDS);
                System.out.println("inert result ....  "+ insetResult);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

java.lang.InterruptedException
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1220)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at java.util.concurrent.ArrayBlockingQueue.offer(ArrayBlockingQueue.java:374)
at thread.BlaockingQueueDemo.main(BlaockingQueueDemo.java:35)
java.lang.InterruptedException
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1220)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at java.util.concurrent.ArrayBlockingQueue.offer(ArrayBlockingQueue.java:374)
at thread.BlaockingQueueDemo.main(BlaockingQueueDemo.java:35)
java.lang.InterruptedException
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1220)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at java.util.concurrent.ArrayBlockingQueue.offer(ArrayBlockingQueue.java:374)
at thread.BlaockingQueueDemo.main(BlaockingQueueDemo.java:35)

put
 /**
     * Inserts the specified element into this queue, waiting if necessary
     * for space to become available.
     *
     * @param e the element to add
     * @throws InterruptedException if interrupted while waiting
     * @throws ClassCastException if the class of the specified element
     *         prevents it from being added to this queue
     * @throws NullPointerException if the specified element is null
     * @throws IllegalArgumentException if some property of the specified
     *         element prevents it from being added to this queue
     */
    void put(E e) throws InterruptedException;

当队列已满时,则该方法(调用该方法的线程)阻塞(等待)。添加元素不能为null

    public static void main(String[] args) {
        BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<String>(1);
        new Thread(()->{
            try {
                while(true){
                    Thread.sleep(1000);
                    blockingQueue.take();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        DateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for(int i=0;i<3;i++){
            boolean insertResult = false;
            try {
                blockingQueue.put("string... "+i);
                System.out.println("put......  "+format.format(new Date()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

put… 2019-09-01 14:49:12
put… 2019-09-01 14:49:13
put… 2019-09-01 14:49:14

二、删除元素

移除元素的方法有: remove /poll /take。

移除元素方法根据移除位置分为两类:

  1. 移除头部元素 : poll, take
  2. 移除任意位置的元素 : remove(obj)
remove
/**
     * Removes a single instance of the specified element from this queue,
     * if it is present.  More formally, removes an element {@code e} such
     * that {@code o.equals(e)}, if this queue contains one or more such
     * elements.
     * Returns {@code true} if this queue contained the specified element
     * (or equivalently, if this queue changed as a result of the call).
     *
     * @param o element to be removed from this queue, if present
     * @return {@code true} if this queue changed as a result of the call
     * @throws ClassCastException if the class of the specified element
     *         is incompatible with this queue
     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if the specified element is null
     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
     */
    boolean remove(Object o);

从队列中移除一个元素(最先匹配到的元素),移除成功返回true。如果队列中不存在该元素则返回false。

 public static void main(String[] args) {
        ArrayBlockingQueue<String> blockingQueue=new ArrayBlockingQueue<String>(5);
        new Thread(()->{
            try {
                while(true){
                    Thread.sleep(1000);
                    Object object =blockingQueue.remove("A");
                    System.out.println(object);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        for(int i=0;i<3;i++){
            boolean insertResult = false;
            try {
                blockingQueue.put("A");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

[A, A]
[A]
[]
[]
[]

poll
 /**
     * Retrieves and removes the head of this queue, waiting up to the
     * specified wait time if necessary for an element to become available.
     *
     * @param timeout how long to wait before giving up, in units of
     *        {@code unit}
     * @param unit a {@code TimeUnit} determining how to interpret the
     *        {@code timeout} parameter
     * @return the head of this queue, or {@code null} if the
     *         specified waiting time elapses before an element is available
     * @throws InterruptedException if interrupted while waiting
     */
    E poll(long timeout, TimeUnit unit)
        throws InterruptedException;

从队列中获取并移除队列头部元素。如果队列为空则方法(调用该方法的线程) 等待指定的时间,如果在此期间还是未获取元素则返回 null。等待时被中断则抛出异常InterruptedException

 public static void main(String[] args) {
        ArrayBlockingQueue<String> blockingQueue=new ArrayBlockingQueue<String>(5);
        new Thread(()->{
            try {
                while(true){
                    Thread.sleep(1000);
                    Object object =blockingQueue.poll(1,TimeUnit.SECONDS);
                    System.out.println(object);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        for(int i=0;i<3;i++){
            boolean insertResult = false;
            try {
                blockingQueue.put("A");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

A
A
A
null
null

take
 /**
     * Retrieves and removes the head of this queue, waiting if necessary
     * until an element becomes available.
     *
     * @return the head of this queue
     * @throws InterruptedException if interrupted while waiting
     */
    E take() throws InterruptedException;

获取并移除队列头部的元素,如果队列为空则方法(调用该方法的线程)阻塞(等待)。阻塞时被中断则抛出异常InterruptedException

 public static void main(String[] args) {
        ArrayBlockingQueue<String> blockingQueue=new ArrayBlockingQueue<String>(5);
        new Thread(()->{
            try {
                while(true){
                    Thread.sleep(1000);
                    Object object =blockingQueue.take();
                    System.out.println(blockingQueue);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        for(int i=0;i<3;i++){
            boolean insertResult = false;
            try {
                blockingQueue.put("A");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

[A, A]
[A]
[]

因为队列中不存在元素时会阻塞。 所以while循环就不会进行执行下去。

小结
  1. 添加元素方法:
    添加元素不能为null,否则抛出 NullPointerException

    法名返回值是否阻塞抛出异常超时等待
    addtrueIllegalStateException ( 队列已满)
    offertrue | false
    offer(E, long, TimeUnit)true | falseInterruptedException(等待时被中断)√(等待指定的时间)
    putvoidInterruptedException(阻塞时被中断)

    如果想要立即返回插入结果,推荐使用 offer 方法

  2. 移除元素方法

    法名返回值是否阻塞抛出异常超时等待
    remove()trueNoSuchElementException(元素不存在)
    remove(e)true | false
    pollE | null
    poll(long,TimeUnit)E | nullInterruptedException(等待时被中断)√(等待指定时间)
    takeEInterruptedException(阻塞时被中断)

小结:
a. remove() 方法和 add(E) 方法对应,操作成功返回true,操作失败抛出异常
b. poll 方法 和 offer(E) 方法对应,操作成功返回true,操作失败返回false。
c. offer(E, long, TimeUnit) 和 poll(long,TimeUnit) 方法对应,操作成功立即返回结果,操作失败会等待指定的时间再尝试操作
d. put 和 take 方法对应, 操作成功立即返回(void),操作失败一直等待。
e. 操作失败是指,向已满的队列中添加元素,从已空的队列中移除元素。

在这里插入图片描述

注:
E: 表示移除元素
remove() 方法不是BlockingQueue 接口中的方法,remove(e) 才是。
此处的阻塞含义和线程状态中的阻塞含义并不相同,此处的阻塞对应线程中的 WAITING状态,超时等待 对应TIMED_WAITING

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值