java阻塞队列的使用

1、介绍

阻塞队列,其实就是满足队列操作(先进先出)的一个数据集合,同时满足存取数据时的阻塞功能。

在这里插入图片描述

  • 先进入阻塞队列的对象,会先被消费掉。
  • 当阻塞队列已满时,生产者线程添加对象操作会被阻塞。
  • 当阻塞队列已空时,消费者线程取出对象操作会被阻塞。

2、API分析

在这里插入图片描述

阻塞队列的直接接口为BlockingQueue,此接口内部定义了操作队列的各种方法。

BlockingQueue间接实现了Collection接口,所以阻塞队列其实就是一个集合,操作集合的各种方法,阻塞队列也满足。

核心方法
方法类型抛出异常阻塞特殊值阻塞超时
添加boolean add(E e);void put(E e);boolean offer(E e);boolean offer(E e,
long timeout, TimeUnit unit);
移除E remove();E take();E poll();E poll(long timeout, TimeUnit unit);
检查E element();E peek();
核心方法详解

boolean add(E e):往队列尾部添加一个元素,成功返回true,队列已满抛出异常。

void put(E e):往队列尾部添加一个元素,队列已满时操作线程阻塞,直到队列不满。

boolean offer(E e):往队列尾部添加一个元素,成功返回true,失败返回false。

boolean offer(E e, long timeout, TimeUnit unit):往队列尾部添加一个元素,成功返回true,队列已满时,线程阻塞等待指定时长后,若队列仍为满,失败返回false。

E remove():返回并移除队列头部的第一个元素,队列已空抛出异常。

E take():返回并移除队列头部的第一个元素,队列已空时操作线程阻塞,直到队列非空。

E poll():返回并移除队列头部的第一个元素,队列已空时返回null。

E poll(long timeout, TimeUnit unit):返回并移除队列头部的第一个元素,队列已空时,线程阻塞等待指定时长后,若队列仍为空,返回null。

E element():仅返回队列头部第一个元素,队列中元素个数不变,队列已空抛出异常。

E peek():仅返回队列头部第一个元素,队列中元素个数不变,队列已空时返回null。

3、常见的阻塞队列

JDK8中BlockingQueue的实现类:

ArrayBlockingQueue:由数组结构组成的有界阻塞队列(必须指定大小)。
LinkedBlockingQueue:由链表结构组成的有界阻塞队列(默认大小Integer.MAX_VALUE,可视为无限大)。
SynchronousQueue:不存储元素的阻塞队列。
DelayQueue:基于PriorityQueue实现的支持延时获取元素的阻塞队列。
PriorityBlockingQueue:支持优先级排序的无界阻塞队列。
DelayedWorkQueue:定制的优先级队列,只能用来存储RunnableScheduledFutures任务。
LinkedTransferQueue:由链表结构组成的无界阻塞队列。

4、演示使用

演示抛出异常的操作
/**
 * 1、添加元素操作
 */
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue = new ArrayBlockingQueue<String>(3);
        queue.add("张三");
        queue.add("李四");
        queue.add("王五");
        System.out.println(queue);
        queue.add("赵六");
    }
}
/**
 * 运行结果,添加第四个元素的时候队列已满,报错
 */
[张三, 李四, 王五]
Exception in thread "main" java.lang.IllegalStateException: Queue full


/**
 * 2、取元素操作
 */
 public class Demo {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue = new ArrayBlockingQueue<String>(3);
        queue.add("张三");
        queue.add("李四");
        System.out.println(queue);

        System.out.println(queue.remove());
        System.out.println(queue.remove());
        //队列里面仅有两个元素,此时队列已空,再调用remove()会报错
        System.out.println(queue.remove());
    }
}
/**
 * 运行结果,队列已空时,再调用remove()会报错
 */
[张三, 李四]
张三
李四
Exception in thread "main" java.util.NoSuchElementException

/**
 * 3、检查元素操作
 */
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue = new ArrayBlockingQueue<String>(3);
        queue.add("张三");
        System.out.println(queue.element());
        queue.remove();

        //此时队列已空,调用element()会抛出异常
        System.out.println(queue.element());
    }
}
/**
 * 运行结果,队列已空时,再调用element()会抛出异常
 */
张三
Exception in thread "main" java.util.NoSuchElementException
演示阻塞的操作
public class Demo {
    static BlockingQueue<String> queue = new ArrayBlockingQueue<String>(3);
    static DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Producer(queue)).start();
        new Thread(new Consumer(queue)).start();
        //queue.take();
    }
}

/**
 * 生产者线程
 */
class Producer implements Runnable{
    BlockingQueue<String> queue = null;

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

    @Override
    public void run() {
        //每秒钟生产一个元素进队列
        for(int i=1;i<=6;i++){
            try {
                TimeUnit.SECONDS.sleep(1);
                String msg = "元素"+i;
                queue.put(msg);
                System.out.println(LocalDateTime.now().format(Demo.format)+" 生产者已放入 "+msg+" 进入队列");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 消费者线程
 */
class Consumer implements Runnable{
    BlockingQueue<String> queue = null;

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

    @Override
    public void run() {
        //每三秒钟从队列消费一个元素
        while (true){
            try {
                TimeUnit.SECONDS.sleep(3);
                //队列元素取完后,若生产者线程不放入元素,此处将一直阻塞
                String msg = queue.take();
                System.out.println(LocalDateTime.now().format(Demo.format)+" 消费者已从队列中取到消息 "+msg);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 运行结果,当队列已满时,生产者线程被阻塞,当队列已空时,消费者线程被阻塞
 */
2022-04-17 13:37:18 生产者已放入 元素1 进入队列
2022-04-17 13:37:19 生产者已放入 元素2 进入队列
2022-04-17 13:37:20 消费者已从队列中取到消息 元素1
2022-04-17 13:37:20 生产者已放入 元素3 进入队列
2022-04-17 13:37:21 生产者已放入 元素4 进入队列
2022-04-17 13:37:23 消费者已从队列中取到消息 元素2
2022-04-17 13:37:23 生产者已放入 元素5 进入队列
2022-04-17 13:37:26 消费者已从队列中取到消息 元素3
2022-04-17 13:37:26 生产者已放入 元素6 进入队列
2022-04-17 13:37:29 消费者已从队列中取到消息 元素4
2022-04-17 13:37:32 消费者已从队列中取到消息 元素5
2022-04-17 13:37:35 消费者已从队列中取到消息 元素6
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值