文章字数:1260,阅读全文大约需要5分钟
JUC包下的14个并发容器,专门应付并发状态下线程安全的问题
介绍
ConcurrentHashMap并发版的HashMapCopyOnWriteArrayList并发版的ArrayListCopyOnWriteArraySet并发版的SetConcurrentLinkedQueue基于链表的并发队列(不阻塞)ConcurrentLinkedDeque基于双向列表的并发队列ConcurrentSkipListMap基于跳表的并发Map
跳表:链表之上加了一层索引,就是一个新的链表,指向源数据的双数索引的位置。这一层的索引之上还可以增加索引,指向本层的双数位置。链表版的二分法。ConcurrentSkipListSet基于跳表的并发SetArrayBlockingQueue阻塞队列基于数组LinkedBlockingQueue阻塞队列基于链表LinkedBlockingDeque阻塞队列基于双链表PriorityBlockingQueue线程安全的优先队列SynchronousQueue读写成对的队列LinkedTransferQueue基于链表的数据交换队列DelayQueue延时队列
一、ConcurrentHashMap
最常见的并发容器之一,常作用于并发场景下的缓存。底层还是哈希表,但是java8中有了优化。
java7采用分段锁,即数据被分成16个部分。每个部分一把锁,各部分之间不冲突。java8放弃了分段锁,采用CAS乐观锁。java8中增加了同哈希值组成的链表长度超过8之后会转换成红黑树
二、CopyOnWriteArrayList
并发版的ArrayList, 底层结构还是数组。原理是增删改的操作会加锁,其中删改会创建新的数组并替换原来的。
适用于读多写少的情况,并且读没有加锁,所以可能读到脏数据。
读的效率高。
三、CopyOnWriteArraySet
并发版的Set, 内部使用CopyOnWriteArrayList实现的。每次add都会遍历内部数据,检查是否重复。不存在执行插入(加锁)
和CopyOnWriteArrayList注意点类似,多了一条数据量不能太大,否则遍历成本过高。
四、ConcurrentLinkedQueue
基于链表实现的并发队列,不阻塞。使用乐观锁CAS保证现存的安全。内部是链表,理论上没有大小限制。
五、ConcurrentLinkedDeque
基于双向链表的并发队列,可以分别对于首尾进行操作。可以先进先出也可以先进后出。
六、ConcurrentSkipListMap
基于跳表SkipList的并发Map, 跳表是用空间换时间的数据结构。
每一层都是上一层的一半数据,类似于二分查找的实现方式来增加搜索效率。
七、ConcurrentSkipListSet
基于跳表的并发Set, 使用ConcurrentSkipListMap实现的
八、ArrayBlockingQueue
基于数组的阻塞队列,构造时需要指定大小。
添加元素时如果数组满了会阻塞,知道有位置可以放。(也可以设置返回或者超时等待)
通过锁ReentrantLock保证线程安全
九、LinkedBlockingQueue
基于链表的阻塞队列,相比不阻塞ConcurrentLinkedQueue多了容量的现在。不设置默认int的最大值
十、LinkedBlockingDeque
和LinkedBlockingQueue类似,底层是双链表
十一、PriorityBlockingQueue
线程安全的优先队列,构造的时候需要传入一个比较器。内部会根据元素的优先级排序。读取的时候会根据优先级从高到低读取。
优先级低的可能会因为一直有更高级的元素而无法被读取。
十二、SynchronousQueue
数据同步交换队列,内部只能存一个元素。每次插入操作必须要取才能再次插入。
任何一个对SynchronousQueue写需要等到一个对SynchronousQueue的读操作,反之亦然
十三、LinkedTransferQueue
基于链表的交换队列,比SynchronousQueue更强大。
实现了TransferQueue接口,通过transfer方法放入元素时如果有线程在阻塞去元素,就会把元素直接给等待队列。如果没有人等待,则放到队列尾部,并阻塞直到有人读取。
十四、DelayQueue
可以使放入的元素在指定延时之后才被消费者取出,元素需要实现Delayed接口