LinkedBlockingQueue是一个线程安全的阻塞队列,它实现了BlockingQueue接口,BlockingQueue接口继承自java.util.Queue接口,并在这个接口的基础上增加了take和put方法,这两个方法正是队列操作的阻塞版本。
LinkedBlockingQueue
首先看看LinkedBlockingQueue的类图
从图中可以看出LinkedBlockingQueue中引入了两把锁takeLock和putLock,显然分别是用于take操作和put操作的。既LinkedBlockingQueue入队和出队用的是不同的锁,那么LinkedBlockingQueue可以同时进行入队和出队操作。
同时,还引入了两个条件变量,notEmpty和notFull,参照生产者消费者模型,当队列不空的时候消费者可以消费,当队列不满的时候,生产者可以生产。所以notEmpty是告诉程序现在队列中有元素,可以执行take操作;notFull告诉程序队列还没满,还可以往里面放。
类图中还有一个count字段,是记录队列中结点个数的,因此对于LinkedBlockingQueue来说,获取队列的size时间复杂度为o(1),capacity为队列的容量,head和last指针分别指向队头和队尾元素。
入队操作
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();//1
int c = -1;
Node<E> node = new Node(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
while (count.get() == capacity) {//2
notFull.await();
}
enqueue(node);//3
c = count.getAndIncrement();//4
if (c + 1 < capacity)
notFull.signal();//5
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();//6
}
1、首先检查需要入队的元素是否为空,若为空抛出InterruptedException异常(1处所示);
2、然后获取putLock锁,判断队列是否已满,如果已满就挂起当前线程,直到notFull这个条件满足(2处所示);
3、到此表明队列未满,可以入队,和普通入队操作一样(3所示);
4、入队后将队列count+1,count采用的是AtomicInteger的原子操作(4所示);
5、再次判断是否已满,如果未满就通知其他线程(5所示)
6、执行完以上步骤后就解putLock锁。c默认为-1,加入队列后结果为0,说明之前队列为空。由于此时锁还在当前线程上,所以不可能出队,也不可能入队,那么在队列不为空的时候就需要安全的唤醒一个出队线程了。
以上就是入队操作的全过程,LinkedBlockingQueue还有非阻塞版本的入队操作:步骤和put操作类似,但也有一些区别:
public boolean add(E e) 在入队不成功的时候会抛出异常;
public boolean offer(E e)不会抛出异常,而是直接返回true or false
offer(E e, long timeout,TimeUnit unit) throws InterruptedException超时版本的offer也是返回true or false。如果在指定时间范围内没有入队成功会阻塞,直到超时抛出异常。
出队操作
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();//1
}
x = dequeue();//2
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();//3
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();//4
return x;
}
1、首先获取takeLock锁,然后判断队列中是否有元素,如果没有元素就阻塞,直到notEmpty条件出现(1所示)
2、然后出队(2所示)
3、出队之后判断队列中是否还有元素,如果还有就发出notEmpty通知其他线程(3所示)
4、执行以上步骤后,表明成功出队,释放takeLock锁。然后发出队列不空的信号。
和入队一样,出队操作也有非阻塞版本,与入队操作一一对应,这里不作分析。
总结
LinkedBlockingQueue是基于链表的队列的阻塞版本,它实现了入队出队分离,效率比较高,而且支持容量限制。但由于它采用的是链表,所以在查找元素时效率一般。
分享到:
相关推荐
《LinkedBlockingQueue深度解析与应用实践》 在Java并发编程领域,`LinkedBlockingQueue`是一个不可或缺的工具。作为`java.util.concurrent`包中的一个线程安全的队列,它基于链表结构实现,具备先进先出(FIFO)的...
《LinkedBlockingQueue与ConcurrentLinkedQueue的比较与应用》 在Java并发编程中,队列是一种重要的数据结构,尤其在多线程环境下的任务调度和数据传递中扮演着关键角色。LinkedBlockingQueue和...
《深入理解LinkedBlockingQueue与单向链表结构》 LinkedBlockingQueue是Java并发包`java.util.concurrent`中的一个先进先出(FIFO)队列,它基于链表结构实现,特别适用于高并发场景。该队列的主要特点是其内部数据...
### 并发队列 ConcurrentLinkedQueue 和阻塞队列 LinkedBlockingQueue 用法详解 #### 一、并发队列 ConcurrentLinkedQueue 概述 `ConcurrentLinkedQueue` 是 Java 并发包 `java.util.concurrent` 提供的一个高性能...
《LinkedBlockingQueue in Java》 Java中的`LinkedBlockingQueue`是`java.util.concurrent`包下的一种线程安全的阻塞队列,它是基于链表结构实现的,具有很好的性能表现。这种队列在多线程环境下的并发操作中被广泛...
"并发容器之ArrayBlockingQueue和LinkedBlockingQueue实现原理详解" ArrayBlockingQueue和LinkedBlockingQueue是Java并发容器中两个常用的阻塞队列实现,分别基于数组和链表存储元素。它们都继承自AbstractQueue类...
本篇文章将深入探讨`LinkedBlockingQueue`,这是一个基于链表结构的无界阻塞队列,常用于线程池的创建中作为任务缓冲队列。 首先,我们来看一下`LinkedBlockingQueue`的底层数据结构。与数组结构的`...
《元素唯一的LinkedBlockingQueue阻塞队列》 在Java并发编程中,`LinkedBlockingQueue`是一种基于链表结构的阻塞队列,它在多线程环境下的性能表现优秀,常用于实现生产者消费者模型。这个队列的一个关键特性是其...
在Java中,阻塞队列(BlockingQueue)是一个很好的实现生产者/消费者模式的工具,而LinkedBlockingQueue则是Java并发包(java.util.concurrent)中提供的一个具体实现。 LinkedBlockingQueue是一个基于链表结构的...
详细分析Java并发集合LinkedBlockingQueue的用法 Java并发集合LinkedBlockingQueue是Java并发集合中的一种阻塞队列实现,使用链表方式实现的阻塞队列。LinkedBlockingQueue的实现主要包括链表实现、插入和删除节点...
Java中的`LinkedBlockingQueue`和`ArrayBlockingQueue`都是`java.util.concurrent`包下的线程安全队列,它们都实现了`BlockingQueue`接口,提供了一种高效、线程安全的数据同步方式。这两种队列在很多方面都有相似之...
ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。 threadFactory:线程工厂,主要用来创建线程:默认值 ...
LinkedBlockingQueue :由容器/列表支持的有界阻塞队列 ConcurrentRingBuffer :由片支持的有界无锁队列 安装 go get - u github . com / theodesp / blockingQueues 用法 非阻塞API queue , _ := NewArrayBlock
通常,我们会选择实现BlockingQueue的类,如ArrayBlockingQueue、LinkedBlockingQueue或PriorityBlockingQueue,根据实际需求选择合适的实现。 例如,我们可以创建一个配置类,如下所示: ```java @Configuration ...
《Java多线程环境下慎用`LinkedBlockingQueue`的`stream`遍历——揭秘JDK BUG》 在Java编程中,线程安全是多线程编程的重要考量因素,而`LinkedBlockingQueue`作为Java并发包中的一个线程安全队列,因其高效的性能...
本实例将探讨如何利用`LinkedBlockingQueue`和Redis队列来实现数据写入MySQL的过程,这对于大型系统中的批量数据处理和并发控制具有重要意义。 首先,`LinkedBlockingQueue`是Java并发库`java.util.concurrent`中的...
在本次实验中,我们深入探讨了多种线程同步的方法,包括synchronized关键字、volatile、ReentrantLock类以及阻塞队列LinkedBlockingQueue。 首先,synchronized关键字是Java中用于实现线程同步的基本手段,它可以...
private final LinkedBlockingQueue<ClientThread> queue = new LinkedBlockingQueue(); public void enqueue(ClientThread client) { try { queue.put(client); } catch (InterruptedException e) { Thread....