Java线程池队列LinkedBlockingQueue的详细原理分析

您所在的位置:网站首页 线程池arrayblockingqueue Java线程池队列LinkedBlockingQueue的详细原理分析

Java线程池队列LinkedBlockingQueue的详细原理分析

2023-10-19 03:39| 来源: 网络整理| 查看: 265

Java线程池队列LinkedBlockingQueue的详细原理分析-刘宇 一、什么是LinkedBlockingQueue?二、LinkedBlockingQueue类图三、BlockingQueue的方法四、LinkedBlockingQueue讲解1、内部使用到的锁2、多种入队方法比较3、源码解析3.1、put方法3.2、offer方法3.3、take方法3.4、poll方法

CSDN博客地址:https://blog.csdn.net/liuyu973971883 文章来源:转载,原文地址:https://blog.csdn.net/weixin_41622183/article/details/88792358,感谢这位老哥的辛勤付出,写的非常棒,各位看完别忘了给这位老哥点个赞啊。如有侵权,请联系删除。

一、什么是LinkedBlockingQueue? LinkedBlockingQueue内部由单链表实现,按 FIFO(先进先出)排序元素。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。添加元素和获取元素都使用了ReentrantLock锁,读写分离的,读写操作可以并行执行。如果不指定容量,默认为Integer.MAX_VALUE,也就是无界队列。通常建议手动设置一个大小。 二、LinkedBlockingQueue类图

在这里插入图片描述

从上图我们可以很清楚的看到 LinkedBlockingQueue 类中关系,Collection 接口我想大家都很熟悉,平时我们在开发中最常用的 List,Set 顶层也是该接口。按照 java 的语言风格,基本是不断抽象出公共接口,子接口或抽象类则在原有的基础上提供独有的方法。

三、BlockingQueue的方法

LinkedBlockingQueue 是 BlockingQueue 的实现类,那我们需要先看看 BlockingQueue 提供了哪些方法。

public interface BlockingQueue extends Queue { //将对象塞入队列,如果塞入成功返回true, 否则返回false。 boolean add(E e); //将对象塞入到队列中,如果设置成功返回true, 否则返回false boolean offer(E e); //将元素塞入到队列中,如果队列中已经满了, //则该方法会一直阻塞,直到队列中有多余的空间。 void put(E e) throws InterruptedException; //将对象塞入队列并设置时间 //如果塞入成功返回 true, 否则返回 false. boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException; //从队列中取对象,如果队列中没有对象, //线程会一直阻塞,直到队列中有对象,并且该方法取得了该对象。 E take() throws InterruptedException; //在给定的时间里,从队列中获取对象, //时间到了直接调用普通的poll方法,为null则直接返回null。 E poll(long timeout, TimeUnit unit) throws InterruptedException; //获取队列中剩余长度。 int remainingCapacity(); //从队列中移除指定的值。 boolean remove(Object o); //判断队列中包含该对象。 public boolean contains(Object o); //将队列中对象,全部移除,并加到传入集合中。 int drainTo(Collection c); //指定最多数量限制,将队列中对象,全部移除,并加到传入的集合中。 int drainTo(Collection c, int maxElements); } 四、LinkedBlockingQueue讲解

看完上面的代码,我们基本知道了 LinkedBlockingQueue 队列有什么方法,简单说就是实现 BlockingQueue 接口的提供的方法。

1、内部使用到的锁 notEmpty 对象在队列从取出值时,如果队列中没有值了,那线程将会堵塞,等待有值进入队列后唤醒线程取值。notFull 对象对象,如果塞值进队列时,队列已经满了,那线程将会堵塞,直到队列中值被消费,唤醒线程去塞入值。 /** 显示锁,在将对象从队列中取出时加的锁 */ private final ReentrantLock takeLock = new ReentrantLock(); /**线程间通信,从队列中取对象,如果队列为空时,就阻塞 */ private final Condition notEmpty = takeLock.newCondition(); /** 显示锁,在将对象塞入队列时加的锁 */ private final ReentrantLock putLock = new ReentrantLock(); /**线程间通信,塞对象入队列,如果队列满时时,就阻塞*/ private final Condition notFull = putLock.newCondition(); 2、多种入队方法比较 入队方法是否阻塞适合队列offer否有界队列put是都可以

其实入队方法还要个 add 的,但是它还是调用 offer 的入队方法,这里就不介绍。offer 入队方式比较适合有界队列,offer 在队列满的时候,入队失败会返回 false,而 put 的方法在队列满的时候,会将线程阻塞。

3、源码解析 3.1、put方法

入队方法,该方法会阻塞

public void put(E e) throws InterruptedException { //对象为空时抛出异常 if (e == null) throw new NullPointerException(); int c = -1; //节点 Node node = new Node(e); //入队锁 final ReentrantLock putLock = this.putLock; //原子类,用于比较是否超过队列边界 final AtomicInteger count = this.count; //显示锁,上可中断锁 putLock.lockInterruptibly(); try { //判断队列是否已经满,满了就乖乖阻塞 while (count.get() == capacity) { notFull.await(); } //入队操作 enqueue(node); //自增(线程安全) c = count.getAndIncrement(); //判断队列是否超过边界 if (c + 1 //对象为空时抛出异常 if (e == null) throw new NullPointerException(); //原子量,用于自增 final AtomicInteger count = this.count; //判断队列是否已经满了,满了直接返回 false if (count.get() == capacity) return false; int c = -1; Node node = new Node(e); //入队锁 final ReentrantLock putLock = this.putLock; //显示锁 putLock.lock(); try { //判断队列是否已经满了 if (count.get() //解锁 putLock.unlock(); } //唤醒消费线程 if (c == 0) signalNotEmpty(); return c >= 0; } 3.3、take方法

出队方法,该方法会阻塞

public E take() throws InterruptedException { E x; int c = -1; final AtomicInteger count = this.count; final ReentrantLock takeLock = this.takeLock; //可中断锁 takeLock.lockInterruptibly(); try { //当队列为空时,阻塞等待 while (count.get() == 0) { notEmpty.await(); } //出队操作 x = dequeue(); //自减 c = count.getAndDecrement(); //判断队列中是否有对象,有就唤醒之前阻塞的线程 if (c > 1) notEmpty.signal(); } finally { //解锁 takeLock.unlock(); } if (c == capacity) signalNotFull(); return x; } 3.4、poll方法

出队方法

public E poll() { final AtomicInteger count = this.count; //队列为空时,返回空 if (count.get() == 0) return null; E x = null; int c = -1; final ReentrantLock takeLock = this.takeLock; //加锁 takeLock.lock(); try { //判断队列中是否有对象 if (count.get() > 0) { //出队操作 x = dequeue(); //自减 c = count.getAndDecrement(); //唤醒其他出队操作阻塞的线程 if (c > 1) notEmpty.signal(); } } finally { //解锁 takeLock.unlock(); } //唤醒其他队列满时阻塞的线程 if (c == capacity) signalNotFull(); return x; }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3