Java并发编程——阻塞队列BlockingQueue

前言

什么是阻塞队列?有那7种阻塞队列?为什么需要阻塞队列?通过剖析JDK 1.8 源码了解源码设计的精髓和巧妙的地方,并运用在我们实际的项目中,他山之石,可以攻玉。

1. 什么是阻塞队列

image.png

感觉并发编程上面的解释不是很容易理解,我们看下源码Doug Lea大佬的注释,意思是阻塞队列支持检索的时候可以等待队列变成非空(也就是阻塞等待), 存储元素的时候,等待空间可用。
BlockingQueue方法有四种形式,具有不同的处理操作的方法,这些操作不能立即得到满足,但可能在将来的某个时候得到满足:

  1. 抛出一个异常
  2. 返回一个特殊值(null 或 false,依赖具体的操作)
  3. 在操作可以成功前,无限期地阻塞当前线程
  4. 在放弃前只在给定的最大时间限制内阻塞。

image.png

2. JDK种7种阻塞队列

JDK 7提供了7个阻塞队列,如下。

  1. ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
  2. LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
  3. PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
  4. DelayQueue:一个使用优先级队列实现的无界阻塞队列。
  5. SynchronousQueue:一个不存储元素的阻塞队列。
  6. LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
  7. LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

2.1 ArrayBlockingQueue

ArrayBlockingQueue是一个用数组实现的有界阻塞队列。此队列按照先进先出(FIFO)的原 则对元素进行排序。

image.png

看下ArrayBlockingQueue 依赖继承关系,底层是以数组Object[] items;保存元素的。

2.2 LinkedBlockingQueue

LinkedBlockingQueue是一个用链表实现的有界阻塞队列。此队列的默认和最大长度为 Integer.MAX_VALUE。此队列按照先进先出的原则对元素进行排序。

2.3 PriorityBlockingQueue

PriorityBlockingQueue是一个支持优先级的无界阻塞队列。默认情况下元素采取自然顺序 升序排列。也可以自定义类实现compareTo()方法来指定元素排序规则,或者初始化PriorityBlockingQueue时,指定构造参数Comparator来对元素进行排序。需要注意的是不能保证同优先级元素的顺序。

2.4 DelayQueue

DelayQueue是一个支持延时获取元素的无界阻塞队列。队列使用PriorityQueue来实现。队 列中的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素。 只有在延迟期满时才能从队列中提取元素。

使用场景:

  1. 缓存系统的设计
  2. 定时任务调度

2.5 SynchronousQueue

SynchronousQueue是一个不存储元素的阻塞队列。每一个put操作必须等待一个take操作,否则不能继续添加元素。

它支持公平访问队列。默认情况下线程采用非公平性策略访问队列。使用以下构造方法可以创建公平性访问的SynchronousQueue,如果设置为true,则等待的线程会采用先进先出的顺序访问队列。

public SynchronousQueue() {
    this(false);
}

public SynchronousQueue(boolean fair) {
    transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}

2.6 LinkedTransferQueue

LinkedTransferQueue是一个由链表结构组成的无界阻塞TransferQueue队列。相对于其他阻 塞队列,LinkedTransferQueue多了tryTransfer和transfer方法。

2.6.1 transfer方法

2.6.2 tryTransfer方法

2.7 LinkedBlockingDeque

LinkedBlockingDeque是一个由链表结构组成的双向阻塞队列。

3. 阻塞队列的实现原理

我们初学线程池可能会有一个疑问,如果队列是空的,消费者会一直等待,当生产者添加元素时,消费者是如何知道当前队列有元素的呢? 如果是你你会怎么去设计?

使用通知模式实现。所谓通知模式,就是当生产者往满的队列里添加元素时会阻塞住生产者,当消费者消费了一个队列中的元素后,会通知生产者当前队列可用。

以JDK ArrayBlockingQueue 源码分析

public ArrayBlockingQueue(int capacity, boolean fair) {
    if (capacity <= 0)
        throw new IllegalArgumentException();
    this.items = new Object[capacity];
    lock = new ReentrantLock(fair);
    // 这个是阻塞队列的关键点所在, 定义了两个条件队列
    notEmpty = lock.newCondition();
    notFull =  lock.newCondition();
}

我们看下put操作,源码不复杂,我简单解释一下while条件,判断如果队列满了, notFull.await() 等待,当队列不满了,继续执行入队操作。

public void put(E e) throws InterruptedException {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == items.length)
            notFull.await();
        enqueue(e);
    } finally {
        lock.unlock();
    }
}

take方法

public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        // 如果队列无元素,则阻塞等待在条件notEmpty上
        while (count == 0)
            notEmpty.await();
            
        // 出队列    
        return dequeue();
    } finally {
        lock.unlock();
    }
}

最后

对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

不用多说,相信大家都有一个共识:无论什么行业,最牛逼的人肯定是站在金字塔端的人。所以,想做一个牛逼的程序员,那么就要让自己站的更高,成为技术大牛并不是一朝一夕的事情,需要时间的沉淀和技术的积累。

现在竞争这么激烈,只有通过不断学习,提高自己,才能保持竞争力。

对于一些不知道学习什么,没有一个系统路线的程序员,这里给大家提供一些学习资料

需要的小伙伴,可以一键三连,点击这里获取免费领取方式

《Java核心知识点合集(283页)》

内容涵盖:Java基础、JVM、高并发、多线程、分布式、设计模式、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat、数据库、云计算等 在这里插入图片描述

《Java中高级核心知识点合集(524页)》

在这里插入图片描述

《Java高级架构知识点整理》

在这里插入图片描述

《Docker从入门到实践》

在这里插入图片描述

《spring could 学习笔记》

在这里插入图片描述

《JVM与性能调优知识点整理》

在这里插入图片描述

《MySQL性能调优与架构设计解析文档》305页

在这里插入图片描述

《Nginx入门到实战》319页

在这里插入图片描述

《Java并发编程》385页

在这里插入图片描述

《1000道 互联网Java工程师面试题 (485页)》

在这里插入图片描述

需要的小伙伴,可以一键三连,点击这里获取免费领取方式 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值