孤舟蓑笠翁,独钓寒江雪

Java 基础 -- 并发集合的使用

概述

前面大多数集合并不适合用在并发应用程序中,因为它们没有控制并发访问数据。如果一些并发任务共享一个数据结构,而这个数据结构并不适合用在并发任务中,你将会有数据不一致的错误,这将影响到程序的正确运行。比如 ArrayList 类。
为了方便开发者并发编程,在 JDK 5.0 中加入了并发包 java.util.concurrent.*,它提供了可以在并发程序中使用的类,本文仅介绍并发结合的特点和使用方法。

效果图

效果图

并发 Map 框架

ConcurrentHashMap

ConcurrentHashMap 是线程安全且高效的 HashMap,底层采用分段的数组+链表实现,线程安全ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的Hashtable,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。

JDK1.8的实现已经摒弃了Segment的概念,而是直接用Node数组+链表+红黑树的数据结构来实现,此时锁加在key上,并发控制使用Synchronized和CAS来操作,整个看起来就像是优化过且线程安全的HashMap,虽然在JDK1.8中还能看到Segment的数据结构,但是已经简化了属性,只是为了兼容旧版本。

ConcurrentSkipListMap

ConcurrentSkipListMap 的 key 是有序的,底层是通过跳表来实现的。

并发 Collection 框架

BlockingQueue

BlockingQueue 就是阻塞队列,它是一个先进先出的队列,当获取队列元素但是队列为空时,会阻塞等待队列中有元素再返回。当添加元素时,如果队列已满,那么等到队列可以放入新元素时再放入。
BlockingQueue 的实现都是线程安全的。
BlockingQueue 通常用于实现生产者-消费者队列的场景,当然,你也可以将它当做普通的 Collection 来用。

ArrayBlockingQueue

数组阻塞队列,它实现了 BlockingQueue 接口。其内部实现是将对象放到一个数组里。

DelayQueue

延迟队列,它实现了 BlockingQueue 接口。只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的Delayed 元素。

LinkedBlockingQueue

链阻塞队列,内部以一个链式结构(链接节点)对其元素进行存储。

PriorityBlockingQueue

具有优先级的阻塞队列,所有插入到 PriorityBlockingQueue 的元素必须实现 java.lang.Comparable 接口。因此该队列中元素的排序就取决于你自己的 Comparable 实现。
基于数组,数据结构为二叉堆.

SynchronousQueue

它的内部同时只能够容纳单个元素。如果该队列已有一元素的话,试图向队列中插入一个新元素的线程将会阻塞,直到另一个线程将该元素从队列中抽走。同样,如果该队列为空,试图向队列中抽取一个元素的线程将会阻塞,直到另一个线程向队列中插入了一条新的元素。

BlockingDeque

阻塞双端队列,在不能够插入元素时,它将阻塞住试图插入元素的线程;在不能够抽取元素时,它将阻塞住试图抽取的线程。

CopyOnWriteArrayList

CopyOnWriteArrayList 可以说是 ArrayList 的多线程版本,它是线程安全的。
它使用了一种叫写时复制的方法,当有新元素添加到 CopyOnWriteArrayList 时,先从原有的数组中拷贝一份出来,然后在新的数组做写操作,写完之后,再将原来的数组引用指向到新数组。