前面的几篇文章中,我们对于 JUC 包中提供的线程安全队列的设计与实现进行了全面的分析。JUC 包为 java 开发人员提供了丰富的线程安全队列实现,以满足不同的性能和应用场景需求。然而,不知道你是否与我一样,在学习了各个线程安全队列的实现机制之后,反而有点犯迷糊,这些线程安全队列我们在具体编码时该如何选择呢?于是我打算写一篇总结性的文章,对各个线程安全队列的特性进行总结。
深入理解 JUC:LinkedTransferQueue
上一篇我们分析了 SynchronousQueue 队列的设计与实现。在 SynchronousQueue 内部定义了一个 Transferer 抽象类,并继承该类基于 Dual Queue 和 Dual Stack 数据结构分别实现了 SynchronousQueue 的公平模式和非公平模式。本篇我们将要介绍的 LinkedTransferQueue 队列在设计思路上与 SynchronousQueue 的公平模式十分相似,二者在底层存储结构选型上都引入了 Dual Queue 数据结构。
LinkedTransferQueue 在 jdk 1.7 被引入,是一个基于 Dual Queue 数据结构实现的无界线程安全队列,其作者 Doug Lea 描述 LinkedTransferQueue 从功能上来说是 ConcurrentLinkedQueue、SynchronousQueue(公平模式),以及 LinkedBlockingQueue 的超集,并且更加实用和高效。
深入理解 JUC:SynchronousQueue
本文我们一起来分析一下 SynchronousQueue 的设计与实现。不同于前面介绍的一系列线程安全队列,SynchronousQueue 从真正意义上来说并不能算是一个队列,而将其理解为一个用于线程之间通信的组件更为恰当。SynchronousQueue 没有容量的概念,一个线程在执行完入队列操作之后,必须等待另外一个线程与之匹配完成出队列后方可继续再次入队列,反之亦然。此外,有别于我们通常理解的队列中的结点只承载元素,SynchronousQueue 中的结点还需要附着对应的操作线程,这些线程在对应的结点上等待被匹配(fulfill)。
深入理解 JUC:DelayQueue
延迟队列 DelayQueue 用于存放具有过期属性的元素,被添加到 DelayQueue 中的元素只有在到达过期时间之后才会出队列,常用于延迟任务调度。DelayQueue 本质上是一个无界的阻塞队列,底层依赖于优先级队列 PriorityQueue 作为存储结构,并使用 ReentrantLock 锁保证线程安全。
深入理解 JUC:PriorityBlockingQueue
优先级队列 PriorityQueue 应该是大家都比较熟悉的一个集合组件,本文将要介绍的 PriorityBlockingQueue 是 PriorityQueue 的线程安全版本。PriorityBlockingQueue 底层依赖于数组作为存储结构,最大容量上限是 Integer.MAX_VALUE - 8
,所以几乎可以将其视为无界的。同 PriorityQueue 一样,PriorityBlockingQueue 同样引入了堆数据结构来编排队列元素的优先级,默认使用最小堆结构。
深入理解 JUC:LinkedBlockingQueue
上一篇我们分析了无界非阻塞线程安全队列 ConcurrentLinkedQueue 的设计与实现,本篇我们继续分析线程安全队列 LinkedBlockingQueue 的实现机制。由 Blocking 字样可以推断出 LinkedBlockingQueue 是阻塞队列,前面我们介绍过阻塞队列和非阻塞队列在实现上的区别,知道阻塞队列一般是基于锁机制来保证线程安全,本文我们就一起来分析一下 LinkedBlockingQueue 是如何基于锁构建线程安全队列的。
深入理解 JUC:ConcurrentLinkedQueue
ConcurrentLinkedQueue 是线程安全的无界非阻塞队列。在 JUC 包中,线程安全的队列按照实现方式可以分为阻塞队列和非阻塞队列两大类,前者基于锁来保证线程安全,而后者则基于 CAS 机制保证线程安全,阻塞队列一般在类名中都带有 Blocking 的字样。
深入理解 JUC:CopyOnWriteArrayList
CopyOnWriteArrayList 是线程安全的 List 实现,底层依赖于数组作为存储结构,并基于 写时复制(CoW: Copy-on-Write)机制 保证线程安全性。CopyOnWriteArrayList 在执行修改操作时会将底层数组复制一份,并在副本上实施修改,最后再更新回底层数组。虽然这样的实现比较消耗内存,但却带来了较高的执行效率,属于拿空间换时间。
深入理解 JUC:Semaphore
前面我们分析了同步器 CountDownLatch 和 CyclicBarrier 的设计和实现,这两个同步器在使用上都有一个共同的特点,就是在构造时需要指定参与的线程数目,然后对计数器执行减值操作。本文将要介绍的 Semaphore 信号量同样在构造时需要指定一个 int 类型 permits 参数,不过该参数并不用于指定参与的线程数目,相反,Semaphore 并不限制参与的线程数,该参数用于限制同一时间最大允许执行的线程数目上限。
深入理解 JUC:CyclicBarrier
上一篇我们分析了 CountDownLatch 同步器的设计与实现,在日常开发中还有另外一个同步器组件 CyclicBarrier 常常令我们容易混淆。在文章 理清 CountDownLatch 与 CyclicBarrier 的区别 中我们曾经总结过二者的区别,并通过示例演示了各自的应用场景。上一篇,我们分析了 CountDownLatch 的实现原理,本文我们继续从源码层面来分析 CyclicBarrier 的设计与实现。