阻塞队列 BlockingQueue

本文详细介绍了Java中的阻塞队列(BlockingQueue)概念,包括其特点、应用(如生产者-消费者模型和数据分发/收集)以及常见的实现类(如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、DelayQueue和SynchronousQueue)。通过源码示例展示了如何在实际项目中使用这些队列进行线程同步和任务调度。
摘要由CSDN通过智能技术生成

阻塞队列

BlockingQueue 是一个接口,不能直接用,要用它的实现类。它的实现基于 ReentrantLock。

阻塞队列的特点

  1. 当队列为空。从队列中获取元素的操作会被阻塞,直到队列中有新的元素可用
  2. 当队列已满时,像队列中添加元素的操作会被阻塞,直到队列中有空位可用

阻塞队列应用

  • 生产者-消费者模型。原因::不需要额外的实现线程同步和唤醒
  • 线程池的任务队列:阻塞队列可以用来作为线程池的任务队列
  • 线程同步:例如多个线程共享一个阻塞队列,当一个线程需要获取某个元素时,如果队列为空,该线程就会被阻塞,直到其他线程将元素添加到队列中。
  • 数据的分发和收集。可用于数据从一个线程分发到其他线程、或者从多个线程收集数据

阻塞队列实现类

1. ArrayBlockingQueue:

​ 特征:基于数组实现,队列容量固定。存/取数据的操作公用同一把锁(默认非公平锁)。无法实现真正意义上存/取操作的并行执行。

​ 分析:由于基于数组,容量固定所以不容易出现内存占用率过高,但是如果容量太小,取数据比存数据的速度慢,那么会造成过多的线程进入阻塞(也可以使用offer()方法达到不阻塞线程), 此外由于存取共用一把锁,所以有高并发和吞吐量的要求情况下,我们也不建议使用ArrayBlockingQueue。

​ 使用场景:更适合次级业务中

2. LinkedBlockingQueue:

​ 特征:LinkedBlockingQueue 基于链表实现,队列容量默认 Integer.MAX_VALUE。存/取数据的操作分别拥有独立的锁,可实现存/取并行执行。

​ 分析:

​ 1、基于链表,数据新增和移除速度块,但是每次存/取数据都会有 Node 对象的新建和移除,所以存在由于 GC 影响性能的可能。

		2、默认容量非常大,所以存储数据的线程基本不会阻塞,但是如果消费速度过低,内存占用可能会飙升。

​ 3、读/取操作锁分离,所以适合并发和吞吐量要求的项目中

​ 使用场景:在项目中的一些核心业务且生产和消费相似的场景中。

如:订单完成的邮件/短信提醒

3. PriorityBlockingQueue:

​ 特征:基于数组实现。队列最大容量 Integer.MAX_VALUE - 8 (减 8 是因为数组的对象头)。根据传入的优先级进行排序,保证按优先级来消费。

​ 分析:优先级阻塞队列中存在一次排序,根据优先级来将数据放入到头部或者尾部。排序带来的损耗因素,有二叉树最小堆排序算法来降低。

​ 使用场景:在项目上有优先级的业务。

VIP 排队购票

4. DelayQueue:

​ 特征:DelayQueue 延迟队列,基于优先级队列来实现。存储元素必须实现 Delayed 接口。该接口继承了 Comparable 接口。

​ 分析:由于基于优先级队列实现。但是它比较的是时间,根据时间倒序或正序排列

​ 使用场景:订单支付超时取消功能;网站刷题倒计时

5. SynchronousQueue:

​ 特征:采用双栈双队列算法的无空间队列或栈。任何一个对 SynchronousQueue 些需要等到一个对 SynchronousQueue 的读操作,任何一个读操作需要等待一个写操作。没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列,会直接将任务交给消费者。

​ 分析:相当于交换通道,不存储任何元素,提供者和消费者是需要组队完成工作,缺少一个将会阻塞队列,直到等到配对为止。

​ 使用场景:线程池 newCachedThreadPool()轻量级别的任务转交:会话转交

源码展示

源码一、优先级队列

public class QueueTest {
static class Ticket implements Comparable<Ticket> {
        private int level;

        public Ticket(int level) {
            this.level = level;
        }


        @Override
        public int compareTo(Ticket o) {
            //优先级高的返回-1
            if (this.level > o.level)
                return -1;
            else
                return 1;
        }
}
public static void main(String[] args) {
        //VIP客户、各大机场的VIP客户的优先登机,加速抢票
        BlockingQueue<Ticket> queue1 = new PriorityBlockingQueue<>();
        Ticket ticket = new Ticket(0);
        Ticket ticket1 = new Ticket(1);
        Ticket ticket2 = new Ticket(2);
        Ticket ticket3 = new Ticket(-1);
        queue1.add(ticket);
        queue1.add(ticket1);
        queue1.add(ticket2);
        queue1.add(ticket3);
        for (; ; ) {
            try {
                System.out.println(queue1.take().level);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}

源码二、延迟队列

public class QueueTest {
    static class Work implements Delayed {
        //名称
        private String name;
        //时长
        private long time;
        public Work(String name, long time, TimeUnit unit) {
            this.name = name;
            this.time = System.currentTimeMillis() + (time > 0 ? unit.toMillis(time) : 0);
        }
        //时间
        @Override
        public long getDelay(TimeUnit unit) {
            return time - System.currentTimeMillis();
        }
        @Override
        public int compareTo(Delayed o) {
            Work work = (Work) o;
            long diff = this.time - work.time;
            if (diff <= 0) {// 改成>=会造成问题
                return -1;
            } else {
                return 1;
            }
        }
    }
public static void main(String[] args) {
        BlockingQueue<Work> queue3 = new DelayQueue<>();
        try {
            Work work = new Work("用户一", 25, TimeUnit.SECONDS);
            Work work2 = new Work("用户二", 5, TimeUnit.SECONDS);
            Work work3 = new Work("用户三", 15, TimeUnit.SECONDS);
            queue3.add(work);
            queue3.add(work2);
            queue3.add(work3);
            for (; ; ) {
                Work work1 = queue3.take();
                System.out.println(work1.name + "," + work1.time);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 11
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值