JUC阻塞队列BlockingQueue讲解

概述

阻塞队列有两个特性:
阻塞:当队列为空时,会阻塞队列弹出操作,直到队列不为空。当队列满了时,会阻塞入队操作,直到队列不满。
队列:FIFO,先进先出。

接口:java.util.concurrent.BlockingQueue。
实现接口:Collection , Iterable , Queue
已知常用实现类:

  • ArrayBlockingQueue :底层为数组的阻塞队列。
  • LinkedBlockingDeque :底层为链表的双端阻塞队列。
  • LinkedBlockingQueue :底层为链表的单端阻塞队列。
  • SynchronousQueue :同步队列
BlockingQueue的四组API

这四组API是添加元素、删除元素、获取队首元素的四组API,每组以是否抛出异常,是否阻塞等待为维度进行切分。

先上总表格:

方式抛出异常有返回值且不抛出异常阻塞等待超时等待
添加add ()offer()put()offer()
移除remove()poll()take()poll()
获取队首元素element()peek()--
测试会抛出异常的方法
public static void testThrowsExceptionApi(){
        //创建一个阻塞队列,容量为3
        BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(3);
        blockingQueue.add(1);
        blockingQueue.add(2);
        blockingQueue.add(3);
        //单单开放下面代码,会在一个容量为3的队列中加入第4个元素,抛出队列已满的异常
        //blockingQueue.add(4);

        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        //单单开放下面代码,在空队列中移除元素,抛出异常
        //System.out.println(blockingQueue.remove());

        //单单开放下面代码,在空队列中获取队首元素,抛出异常
        //System.out.println(blockingQueue.element());
    }

正常情况:
在这里插入图片描述
往满队列中添加元素:
在这里插入图片描述
往空队列中移除元素:
在这里插入图片描述
往空队列获取队首元素:
在这里插入图片描述

测试不抛出异常且有返回值的Api
 public static void testNonThrowsExceptionApi(){
        //创建一个阻塞队列,容量为3
        BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(3);

        //添加元素,成功返回true,否则返回false
        System.out.println(blockingQueue.offer(1));
        System.out.println(blockingQueue.offer(2));
        System.out.println(blockingQueue.offer(3));
        System.out.println(blockingQueue.offer(4));

        //移除元素,成功返回元素值,失败返回null
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());

        //获取队首元素,成功返回元素值,失败返回null
        System.out.println(blockingQueue.peek());
    }

结果:都没有抛出异常。
在这里插入图片描述

测试阻塞等待Api
 public static void testBlockWaitApi() throws InterruptedException {
        //创建一个阻塞队列,容量为3
        BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(3);
        blockingQueue.put(1);
        blockingQueue.put(2);
        blockingQueue.put(3);
        //如果打开下面代码。因为此时队列已满,所以会一直阻塞在这里,直到队列不满为止
        //blockingQueue.put(4);

        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        //如果打开下面代码。因为此时队列为空,所以会一直阻塞在这里,直到队列不为空为止
        //System.out.println(blockingQueue.take());

    }

结果:
添加时阻塞:会一直阻塞住线程
在这里插入图片描述
移除时阻塞:尝试获取空数组元素时,被阻塞住了。
在这里插入图片描述
没有阻塞等待的获取队首Api。

测试阻塞超时等待
public static void testBlockWaitApiWithTimeout(){
        //创建一个阻塞队列,容量为3
        BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(3);
        try {
            System.out.println(blockingQueue.offer(1, 3, TimeUnit.SECONDS));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            System.out.println(blockingQueue.offer(2, 3, TimeUnit.SECONDS));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            System.out.println(blockingQueue.offer(3, 3, TimeUnit.SECONDS));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            //如果打开下面代码。因为此时队列已满,所以会一直阻塞在这里,直到队列不满或者三秒超时返回false
            System.out.println(blockingQueue.offer(4, 3, TimeUnit.SECONDS));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        try {
            System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //如果打开下面代码。因为此时队列为空,所以会一直阻塞在这里,直到队列不为空或者等待超时3秒返回null为止
        try {
            System.out.println(blockingQueue.poll(3,TimeUnit.SECONDS));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

结果:
在这里插入图片描述
超时等待没有对应的获取队首元素API。

同步队列SynchronousQueue

同步队列添加元素后,就会阻塞当前线程,然后等待其他线程移除该元素后,才会唤醒那个线程。可以使用它来做一对一的线程间通信。

public class SynchronousQueueDemo {

    public static void main(String[] args) {
        SynchronousQueue<Integer> synchronousQueue = new SynchronousQueue<>();
        new Thread(()->{
            try {
                System.out.println("添加元素1前");
                synchronousQueue.put(1);
                System.out.println("添加元素1后");

                System.out.println("添加了元素2前");
                synchronousQueue.put(2);
                System.out.println("添加元素2后");
                System.out.println("添加元素3前");
                synchronousQueue.put(3);
                System.out.println("添加元素3后");
            }catch (InterruptedException e){

            }

        }).start();

        
        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println("释放了元素" + synchronousQueue.take());

                TimeUnit.SECONDS.sleep(3);
                System.out.println("释放了元素" + synchronousQueue.take());

                TimeUnit.SECONDS.sleep(3);
                System.out.println("释放了元素" + synchronousQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

在这里插入图片描述
由结果可以看出,队列添加元素之后,就会阻塞住线程,然后等待另一个线程移除该元素,该线程也会被唤醒。所以先打印添加元素前,然后添加元素,之后线程阻塞,所以没有先打印添加元素后,而是先打印释放元素,然后添加线程被唤醒,就打印添加元素后。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值