多线程篇(阻塞队列- LinkedBlockingDeque)(持续更新迭代)

本文主要是介绍多线程篇(阻塞队列- LinkedBlockingDeque)(持续更新迭代),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、LinkedBlockingDeque是什么

二、核心属性详解

三、核心方法详解

addFirst(E e)

offerFirst(E e)

putFirst(E e)

removeFirst()

pollFirst()

takeFirst()

其他

四、总结


一、LinkedBlockingDeque是什么

首先queue是一种数据结构,一个集合中,先进后出,有两种实现的方式,数组和链表。

从尾部追加,从头部获取。

Deque是两端都可以添加,且两端都可以获取,所以它的方法会有一系列的Last,Frist语义,添加或获取等操作

会指明哪个方向的,这也是Deque接口的定义。

那如果你不指定语义 如add()方法,他会默认调用addLast

综上所述,LinkedBlockingDeque是一个线程安全的双端阻塞队列。

二、核心属性详解

相对于LinkedBlockingQueue 他只能使用一把锁,不能分成put 和 take两把锁。

因为此时双端都可以put 和 take,所以只能使用一个锁,通过锁,对其链表实现线程安全的操作。

    //队列的头尾节点transient Node<E> first;transient Node<E> last;//队列中元素的数量private transient int count;//指定的队列的容量,默认Int最大值private final int capacity;//实现线程安全的使用的锁final ReentrantLock lock = new ReentrantLock();//获取元素的时候如果空了会使用它让其自己等待private final Condition notEmpty = lock.newCondition();//添加元素的时候如果满了(count == capacity)会使用它让其自己等待private final Condition notFull = lock.newCondition();

三、核心方法详解

下面会列举First系列的方法,因为last系列相对于first只是链表方向不一样,操作都是一致的。

addFirst(E e)

调用offerFirst 如果未成功 则抛出异常

    public void addFirst(E e) {if (!offerFirst(e))throw new IllegalStateException("Deque full");}

offerFirst(E e)

在链表的头部添加一个元素,使用ReentrantLock 保证线程安全

    public boolean offerFirst(E e) {if (e == null) throw new NullPointerException();Node<E> node = new Node<E>(e);//获取锁final ReentrantLock lock = this.lock;lock.lock();try {//把当前元素对应的节点放到头结点那里return linkFirst(node);} finally {lock.unlock();}}private boolean linkFirst(Node<E> node) {//如果元素已经超出容量,返回添加失败if (count >= capacity)return false;//链表的操作,用的是双向链表,first变成自己,之前的first是自己的nextNode<E> f = first;node.next = f;first = node;if (last == null)last = node;elsef.prev = node;//元素统计数量加1++count;//唤醒那些因为获取不到元素而阻塞的线程notEmpty.signal();return true;}

putFirst(E e)

相对于offer一个元素 如果元素数量已到达容量上线,会阻塞住等待元素被取走才放入

在juc下面 put add take等语义都是一致的

    public void putFirst(E e) throws InterruptedException {if (e == null) throw new NullPointerException();Node<E> node = new Node<E>(e);//获取锁final ReentrantLock lock = this.lock;lock.lock();try {//添加失败就阻塞住等待唤醒while (!linkFirst(node))notFull.await();} finally {lock.unlock();}}

removeFirst()

从头结点移除一个元素,调用的是pollFirst,拿出元素返回,元素==null会抛出异常

    public E removeFirst() {E x = pollFirst();if (x == null) throw new NoSuchElementException();return x;}

pollFirst()

取出first元素并返回,会返回null


    public E pollFirst() {//加锁final ReentrantLock lock = this.lock;lock.lock();try {// 取出first, 链表的操作和count的维护以及唤醒添加元素因为容量到达上线的等待的线程return unlinkFirst();} finally {lock.unlock();}}

takeFirst()

获取一个first元素,区别poll 在于会阻塞等待

    public E takeFirst() throws InterruptedException {final ReentrantLock lock = this.lock;//获取锁lock.lock();try {E x;//拿不到就阻塞等待,等待添加元素的时候被其他线程唤醒while ( (x = unlinkFirst()) == null)notEmpty.await();return x;} finally {lock.unlock();}}

其他

对于last系列方法,只是链表的操作方向不一样而已

其次默认的不带last 和 first系列的方法,即原始的add put等方法,可以等同LinkedBlockingQueue。

LinkedBlockingDeque内部是一个双向链表,支持了链表两端操作,所以方法不一一介绍,原理都是一样。

四、总结

LinkedBlockingDeque使用双端队列,通过ReentrantLock保证线程安全,实现了双端的线程安全的阻塞队列。

这篇关于多线程篇(阻塞队列- LinkedBlockingDeque)(持续更新迭代)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1148146

相关文章

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

SpringBoot中使用 ThreadLocal 进行多线程上下文管理及注意事项小结

《SpringBoot中使用ThreadLocal进行多线程上下文管理及注意事项小结》本文详细介绍了ThreadLocal的原理、使用场景和示例代码,并在SpringBoot中使用ThreadLo... 目录前言技术积累1.什么是 ThreadLocal2. ThreadLocal 的原理2.1 线程隔离2

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH

C#多线程编程中导致死锁的常见陷阱和避免方法

《C#多线程编程中导致死锁的常见陷阱和避免方法》在C#多线程编程中,死锁(Deadlock)是一种常见的、令人头疼的错误,死锁通常发生在多个线程试图获取多个资源的锁时,导致相互等待对方释放资源,最终形... 目录引言1. 什么是死锁?死锁的典型条件:2. 导致死锁的常见原因2.1 锁的顺序问题错误示例:不同

解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)

《解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)》该文章介绍了使用Redis的阻塞队列和Stream流的消息队列来优化秒杀系统的方案,通过将秒杀流程拆分为两条流水线,使用Redi... 目录Redis秒杀优化方案(阻塞队列+Stream流的消息队列)什么是消息队列?消费者组的工作方式每

浅析Rust多线程中如何安全的使用变量

《浅析Rust多线程中如何安全的使用变量》这篇文章主要为大家详细介绍了Rust如何在线程的闭包中安全的使用变量,包括共享变量和修改变量,文中的示例代码讲解详细,有需要的小伙伴可以参考下... 目录1. 向线程传递变量2. 多线程共享变量引用3. 多线程中修改变量4. 总结在Rust语言中,一个既引人入胜又可

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

Redis延迟队列的实现示例

《Redis延迟队列的实现示例》Redis延迟队列是一种使用Redis实现的消息队列,本文主要介绍了Redis延迟队列的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录一、什么是 Redis 延迟队列二、实现原理三、Java 代码示例四、注意事项五、使用 Redi

Redis缓存问题与缓存更新机制详解

《Redis缓存问题与缓存更新机制详解》本文主要介绍了缓存问题及其解决方案,包括缓存穿透、缓存击穿、缓存雪崩等问题的成因以及相应的预防和解决方法,同时,还详细探讨了缓存更新机制,包括不同情况下的缓存更... 目录一、缓存问题1.1 缓存穿透1.1.1 问题来源1.1.2 解决方案1.2 缓存击穿1.2.1

Linux Mint Xia 22.1重磅发布: 重要更新一览

《LinuxMintXia22.1重磅发布:重要更新一览》Beta版LinuxMint“Xia”22.1发布,新版本基于Ubuntu24.04,内核版本为Linux6.8,这... linux Mint 22.1「Xia」正式发布啦!这次更新带来了诸多优化和改进,进一步巩固了 Mint 在 Linux 桌面