并发容器
1 阻塞队列
BlockingQueue一般用于生产者-消费者模式,生产者往队列中添加元素,消费者从队列中取元素,BlockingQueue就是存放元素的容器
方法 | 抛出异常 | 返回特殊值 | 一直阻塞 | 超时退出 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除 | remove() | poll() | take() | poll(time, unit) |
检查 | element() | peek() |
不能往阻塞队列中插入null,会抛出空指针异常
1.1 ArrayBlockingQueue
由数组结构组成的有界阻塞队列,具备数组的特性
可以初始化大小,但一旦初始化就不能改变。构造方法可以指定是公平锁还是非公平锁
1.2 LinkedBlockingQueue
由链表结构组成的有界阻塞队列,具备链表的特性
默认大小是Integer.MAX_VALUE,也可以指定
1.3 DelayQueue
没有大小限制,当队列中的元素延迟时间到了,才能取出
生产者不会被阻塞,只有消费者会被阻塞
1.4 PriorityBlockingQueue
基于优先级的无界阻塞队列
内部采用非公平锁
1.5 SynchronousQueue
没有任务内部容量,每个put必须等待一个take,反之亦然
2 并发Map
2.1 HashTable
采用全局锁,synchronized保证线程安全,效率低下
数据结构采用的是数组+链表
2.2 ConcurrentHashMap
2.2.1 JDK 1.7
采用分段锁,将数据分段,对每一段数据配备一把锁,当一个线程占用锁访问其中一段数据时,其他段数据仍旧可以被访问
可重入锁,由Segment数组组成,每个Segment里包含HashEntry数组,每个HashEntry是一个链表结构的元素
2.2.2 JDK 1.8
取消了分段锁,采用自旋CAS和synchronized保证并发安全
结构采用的是数组+链表/红黑树,synchronized只锁当前链表或红黑树的首节点,这样只要hash不冲突就不会产生并发
与HashMap一样,链表长度达到8时会转换为红黑树
2.3 ConcurrentSkipListMap
底层数据结构使用跳表,是一种空间换时间的数据结构,使用CAS保证并发安全性
3 并发List
JDK并没有提供线程安全的List类,对于List来说,很难开发一个通用并且没有并发瓶颈的线程安全List
3.1 Vector
通过对方法加锁synchronized实现并发安全性,效率低下
4 并发Set
4.1 ConcurrentSkipListSet
底层使用ConcurrentSkipListMap实现
5 并发Queue
5.1 ConcurrentLinkedQueue
5.2 ConcurrentLinkedDeque
以上两个结构都是采用CAS实现线程安全的
6 CopyOnWrite
CopyOnWrite容器即写时复制容器,当往容器中增加元素时,复制一份新容器,往新容器中增加元素,然后再将原容器的引用指向新容器
好处是并发场景下读操作不需要加锁,达到读写分离目的
6.1 CopyOnWriteArrayList
优点:适用于读多写少的场景,读操作不加锁,写操作加锁
缺点:拷贝容器会增加内存压力,读操作是在老的容器中读