目录
一、同步容器
1.1 什么是同步容器
Java的集合容器框架中,主要四大类别有List、Map、Queue、Set,其中ArrayList、LinkedList、HashMap这些容器都是非线程安全的。如果有多个线程并发地访问这些容器,就会出现问题。
因此,在编写程序时,在多线程环境下必须要求程序员手动地在任何访问这些容器的地方进行同步处理,这样导致在使用这些容器的时候非常不方便。
所以Java先提供了同步容器供用户使用。
同步容器可以简单地理解为通过synchronized来实现同步的容器,比如Vector、Hashtable以及SynchronizedList等容器。
1.2 同步容器分类
- Vector
- Stack
- HashTable
- Collections.synchronized方法生成
1.3 同步容器面临的问题
通过查看Vector、Hashtable等这些同步容器的实现代码,可以看到这些容器实现线程安全的方式就是将它们的状态封装起来,并在需要同步的方法上加上关键字synchronized。
这样做的代价是削弱了并发性,当多个线程共同竞争锁时,吞吐量就会降低。
因此为了解决同步容器的性能问题,所以才有了并发容器。
二、并发容器
2.1 什么是并发容器
java.util.concurrent包中提供了多种并发类容器
并发类容器是专门针对多线程并发设计的,使用了锁分段技术,只对操作的位置进行同步操作,但是其他没有操作的位置其他线程仍然可以访问,提高了程序的吞吐量。
采用了CAS算法和部分代码使用synchronized锁保证线程安全。
2.2 并发容器分类
1、ConcurrentHashMap
- 对应的非并发容器:HashMap
- 目标:代替Hashtable、synchronizedMap
- 原理:JDK6中采用一种更加细粒度的加锁机制Segment“分段锁”,JDK8中采用CAS无锁算法。
2、CopyOnWriteArrayList
- 对应的非并发容器:ArrayList
- 目标:代替Vector、synchronizedList
- 原理:利用高并发往往是读多写少的特性,对读操作不加锁,对写操作,先复制一份新的集合,在新的集合上面修改,然后将新集合赋值给旧的引用,并通过volatile保证其可见性,当然写操作的锁时必不可少的了。
3、CopyOnWriteArraySet
- 对应的非并发容器:HashSet
- 目标:代替synchronizedSet
- 原理:基于CopyOnWriteArrayList实现,唯一的不同是在add时调用的是CopyOnWriteArrayList的addIfAbsent方法,其遍历当前Object数组,如Object数组中已有了当前元素,则直接返回,如果没有,则放入Object数组的尾部,并返回。
4、ConcurrentSkipListMap
- 对应的非并发容器:TreeMap
- 目标:代替synchronizedSortedMap
- 原理:Skip list(跳表)是一种可以代替平衡树的数据结构,默认是按照key值升序的。
5、ConcurrentSkipListSet
- 对应的非并发容器:TreeSet
- 目标:代替synchronizedSortedSet
- 原理:内部基于ConcurrentSkipListMap实现。
6、ConcurrentLinkedQueue
不会阻塞的队列
- 对应的非并发容器:Queue
- 原理:基于链表实现的FIFO队列
7、LinkedBlockingQueue、ArrayBlockingQueue、PriorityBlockingQueue
- 对应的非并发容器:BlockingQueue
- 特点:拓展了Queue,增加了可阻塞的插入和获取等操作
- 原理:通过ReentrantLock实现线程安全,通过Condition实现阻塞和唤醒
- 实现类: LinkedBlockingQueue:基于链表实现的可阻塞的FIFO队列
ArrayBlockingQueue:基于数组实现的可阻塞的FIFO队列
PriorityBlockingQueue:按优先级排序的队列