奉劝那些刚参加工做的学弟学妹们:要想学好并发编程,这些并发容器的坑是你必需要注意的!!(建议收藏)

2021年09月15日 阅读数:1
这篇文章主要向大家介绍奉劝那些刚参加工做的学弟学妹们:要想学好并发编程,这些并发容器的坑是你必需要注意的!!(建议收藏),主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

你们好,我是冰河~~java

在上一篇《亿级流量高并发秒杀系统商品“超卖”了,只因使用的JDK同步容器中存在这两个巨大的坑!!(踩坑实录,建议收藏)》中,咱们主要一块儿学习了JDK中同步容器的两个坑,一个是在使用同步容器时可能会出现 竞态条件 的问题,一个是在使用同步容器时用 迭代器遍历容器 可能会踩坑。编程

其实,在JDK1.5以前的线程安全的容器,大多数都是指同步容器,使用同步容器进行并发编程时,最大的问题就是性能不好。由于同步容器中的全部方法都是使用synchronized锁进行互斥,串行度过高了,没法真正的作到并行。数组

因此,在JDK1.5以后,JDK中提供了并发性能更好的容器。JDK1.5及以后的版本中,提供的线程安全的容器,通常被称为并发容器。安全

并发容器

与同步容器同样,并发容器在整体上也能够分为四大类,分别为:List、Set、Map和Queue。整体上以下图所示。并发

奉劝那些刚参加工做的学弟学妹们:要想学好并发编程,这些并发容器的坑是你必需要注意的!!(建议收藏)_精通高并发系列

接下来,咱们分别介绍下这些并发容器在使用时的注意事项和避免踩到的坑。ide

List

并发容器中的List相对来讲比较简单,就一个CopyOnWriteArrayList。你们能够从字面的意思中就可以体会到:CopyOnWrite,在写的时候进行复制操做,也就是说在进行写操做时,会将共享变量复制一份。那这样作有什么好处呢?最大的好处就是:读操做能够作到彻底无锁化高并发

在CopyOnWriteArrayList内部维护了一个数组,成员变量array指向这个数组,其核心源代码以下所示。性能

private transient volatile Object[] array;
final Object[] getArray() {
	return array;
}
final void setArray(Object[] a) {
	array = a;
}

当进行操做时,都是基于array指向的这个内部数组进行的。例如,咱们使用Iterator迭代器遍历这个数组时,会按照下图所示的方式进行读操做。学习

奉劝那些刚参加工做的学弟学妹们:要想学好并发编程,这些并发容器的坑是你必需要注意的!!(建议收藏)_并发编程_02

若是在遍历CopyOnWriteArrayList时发生写操做,例如,向数组中增长一个元素时,CopyOnWriteArrayList则会将内部的数组复制一份出来,而后会在新复制出来的数组上添加新的元素,添加完再将array指向新的数组,以下图所示。线程

奉劝那些刚参加工做的学弟学妹们:要想学好并发编程,这些并发容器的坑是你必需要注意的!!(建议收藏)_并发编程_03

对于CopyOnWriteArrayList的其余写操做和添加元素的操做原理相同,这里就再也不赘述了。

使用CopyOnWriteArrayList时须要注意的是:

  • CopyOnWriteArrayList只适合写操做比较少的场景,而且可以容忍读写操做在短期内的不一致。
  • CopyOnWriteArrayList的迭代器是只读的,不支持写操做。

Set

对于Set接口来讲,并发容器中主要有两个实现类,一个是CopyOnWriteArraySet,另外一个是ConcurrentSkipListSet。其中,CopyOnWriteArraySet的使用场景、原理与注意事项和CopyOnWriteArrayList一致。而ConcurrentSkipListSet的使用场景、原理和注意事项和下文的ConcurrentSkipListMap一致。这里,我就再也不赘述啦。

Map

在并发容器中,Map接口的实现类主要有ConcurrentHashMap和ConcurrentSkipListMap,而ConcurrentHashMap和ConcurrentSkipListMap最大的区别就是:ConcurrentHashMap的Key是无序的,而ConcurrentSkipListMap的Key是有序的。

在使用ConcurrentHashMap和ConcurrentSkipListMap时,须要注意的是:ConcurrentHashMap和ConcurrentSkipListMap的Key和Value都不能为空。

这里,咱们能够将Map相关的类总结成一个表格,以下所示。

Map的实现类 Key是否可为空 Value是否可为空 是不是线程安全的
HashMap
TreeMap
HashTable
ConcurrentHashMap
ConcurrentSkipListMap

这样,你们记忆起来就方便多了。

这里,ConcurrentSkipListMap是基于“跳表”实现的,跳表的插入、删除、查询的平均时间复杂度为O(log n),这些时间复杂度在理论上与线程数没有关系。若是要追求性能的话,能够尝试使用ConcurrentSkipListMap。

Queue

在Java的并发容器中,Queue相对来讲比较复杂。咱们先来了解几个概念:

  • 阻塞队列:阻塞通常就是指当队列已满时,入队操做会阻塞;当队列为空时,出队操做就会阻塞。
  • 非阻塞队列:队列的入队和出队操做不会阻塞。
  • 单端队列:队列的入队操做只能在队尾进行,队列的出队操做只能在队首进行。
  • 双端队列:队列的入队操做和出队操做均可以在队首和队尾进行。

咱们能够将上述的队列进行组合,将队列分为单端阻塞队列、双端阻塞队列、单端非阻塞队列和双端非阻塞队列。

奉劝那些刚参加工做的学弟学妹们:要想学好并发编程,这些并发容器的坑是你必需要注意的!!(建议收藏)_并发编程_04

在Java的并发容器中,会使用明显的标识来区分不一样类型的队列。

  • 阻塞队列一个明显的标识就是使用Blocking修饰,例如,ArrayBlockingQueue和LinkedBlockingQueue都是阻塞队列。
  • 单端队列会使用Queue标识,例如ArrayBlockingQueue和LinkedBlockingQueue也是单端队列。
  • 双端队列会使用Deque标识,例如LinkedBlockingDeque和ConcurrentLinkedDeque都是双端队列。

接下来,咱们就分别简单聊聊这四种类型的队列。

单端阻塞队列

在Java的并发容器中,单端阻塞队列的主要实现是BlockingQueue,主要包括:ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、LinkedTransferQueue、PriorityBlockingQueue和DelayQueue。

奉劝那些刚参加工做的学弟学妹们:要想学好并发编程,这些并发容器的坑是你必需要注意的!!(建议收藏)_并发编程_05

单端阻塞队列的内部通常会有一个队列。

在实现上,内部的队列能够是数组,例如ArrayBlockingQueue,也能够是链表,例如LinkedBlockingQueue。

也能够在内部不存在队列,例如SynchronousQueue,SynchronousQueue实现了生产者的入队操做必须等待消费者的出队操做完成以后才能进行。

LinkedTransferQueue集成了LinkedBlockingQueue和SynchronousQueue的优势,而且性能比LinkedBlockingQueue好。

PriorityBlockingQueue实现了按照优先级进行出队操做,也就是说,队列元素在PriorityBlockingQueue内部能够按照某种规则进行排序。

DelayQueue是延时队列,实现了在一段时间后再出队的操做。

双端阻塞队列

双端阻塞队列的实现主要是LinkedBlockingDeque。示意图以下所示。

奉劝那些刚参加工做的学弟学妹们:要想学好并发编程,这些并发容器的坑是你必需要注意的!!(建议收藏)_精通高并发系列_06

单端非阻塞队列

单端非阻塞队列的实现主要是ConcurrentLinkedQueue,示意图以下所示。

奉劝那些刚参加工做的学弟学妹们:要想学好并发编程,这些并发容器的坑是你必需要注意的!!(建议收藏)_精通高并发系列_07

双端非阻塞队列

双端非阻塞队列的实现主要是ConcurrentLinkedDeque,示意图以下所示。

奉劝那些刚参加工做的学弟学妹们:要想学好并发编程,这些并发容器的坑是你必需要注意的!!(建议收藏)_亿级流量_08

有界与无界队列

使用队列时,还要注意队列的有界与无界问题,也就是在使用队列时,须要注意队列是否有容量限制

在实际工做中,通常推荐使用有界队列。由于无界队列很容易致使内存溢出的问题。在Java的并发容器中,只有ArrayBlockingQueue和LinkedBlockingQueue支持有界,其余的队列都是无界队列。

在使用时,必定要注意内存溢出问题。

总结

今天咱们主要介绍了JDK1.5以后提供的并发容器,主要包括:List、Set、Map和Queue,而Queue又能够分为:单端阻塞队列、双端阻塞队列、单端非阻塞队列和双端非阻塞队列。对于每种并发容器,咱们简单介绍了其基本原理和注意事项。

写在最后

若是你想进大厂,想升职加薪,或者对本身现有的工做比较迷茫,均可以私信我交流,但愿个人一些经历可以帮助到你们~~