一.线程安全容器
1.List(CopyOnWriteArrayList)
CopyOnWriteArrayList内部维护一个数组,成员变量arr指向这个数组,读操作也就是迭代Iterator遍历的就是这个数组,如果在读的时候,同时存在写操作的时候,会将arr复制一份,然后在复制的数组上进行进行元素的添加,执行操作完成操作之后将arr指向新的数组。
适用与:读多写很少的场景
优点:读无锁,读的效率很高
缺点:浪费内存,读写的短暂不一致
注意:CopyOnWriteArrayList的迭代器不支持增删改,只支持读
2.Map
ConcurrentHashMap 的 key 是无序的,而 ConcurrentSkipListMap 的 key 是有序的。所以如果你需要保证 key 的顺序,就只能使用 ConcurrentSkipListMap。
ConcurrentSkipListMap 里面的 SkipList 本身就是一种数据结构“跳表”。跳表插入、删除、查询操作平均的时间复杂度是 O(log n),理论上和并发线程数没有关系,所以在并发度非常高的情况下,若你对 ConcurrentHashMap 的性能还不满意,可以尝试一下 ConcurrentSkipListMap。
3.Set
CopyOnWriteArraySet 和 ConcurrentSkipListSet,使用场景可以参考CopyOnWriteArrayList 和 ConcurrentSkipListMap。
4.Queue
队列可以分为:阻塞和非阻塞,单端和双端,组合起来共四类:
4.1 单端阻塞队列
ArrayBlockingQueue:数组结构,单锁,支持有界
LinkedBlockingQueue:链表结构,双锁,最大容量Integer.MAX_VALUE,效率相比ArrayBlockQueue更高,支持有界
SynchronousQueue:容量为0,语义和之前的Exchanger是一样的,理解为手递手的传递东西,其中take和put方法都是阻塞的。
***线程池中的应用比较多,但是我不会,查了一些资料也是说有应用,但是具体的应用还是不清楚。***
SynchronousQueue的应用案例:jdk提供的CachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
LinkedTransferQueue:像是SynchronousQueue的加强版,可以传递多个参数,并且put方法不再是阻塞的了,但是提供了一个强大的transfer方法,阻塞的等待消费者消费。并且效率比SynchronousQueue和LinkedBlockingQueue的效率更高。
PriorityBlockingQueue:堆结构的阻塞队列,支持优先级的出队
DelayQueue:支持等待时间的优先出队
4.2双端阻塞队列
LinkedBlockingDeque。
4.3单端非阻塞队列
ConcurrentLinkedQueue。
4.4双端非阻塞队列
ConcurrentLinkedDeque。
总结
上诉的队列中,只有ArrayBlockingQueue和LinkedBlockingQueue(ConcurrentLinkedDeque)是有界的,其他均是无界的,使用的时候尽量使用有界队列。
Queue相对于list的区别,添加了对线程友好的API:offer、peek、poll
Queue子类BlockingQueue添加了对象成友好的API:put和take(阻塞的)。
对于容器理解的还是比较少,目前只是清楚表面一点,以后在扩充。