# 6.9并发容器

并发容器中，线程安全的集合和map

* **ArrayList → CopyOnWriteArrayList**

  写操作时复制。当有新元素添加到CopyOnWriteArrayList时，从原数组上拷贝一份副本，在副本上做写操作，完成写操作后，将原来的数组指向副本。

  注意：CopyOnWriteArrayList都是在加锁的情况下进行写操作，以避免多线程时出现多个副本，把数组搞乱了。

CopyOnWriteArrayList的缺点：

* 写操作时需要拷贝数组，占用内存，当数组数据较多时，可能出现 young GC或full GC
* 不能用于实时的的场景，由于copy出副本、新添加元素都需要时间，读取时的数据可能是旧的，虽然CopyOnWriteArrayList能做到最终的一致性，但没法满足实时性的要求

CopyOnWriteArrayList更适合读多写少的场景

CopyOnWriteArrayList读操作时都是在原数组上读的，不需要加锁，而写操作要加锁，避免多个线程并发修改时复制出多个副本

* **HashSet、TreeSet → CopyOnWriteArraySet、ConcurrentSkipListSet**

  CopyOnWriteArraySet是基于CopyOnWriteArrayList实现的，适合于很小的集合，只读操作大于写入操作的场景。

  ConcurrentSkipListSet JDK6新增的类，很TreeSet一样，支持自然排序，可以在构造的时候自定义比较器，和其他Set一样，ConcurrentSkipListSet是基于Map集合的。对于contains()、add()、remove()方法都是线程安全的，但是对于批量操作，比如containsAll()、addAll()、removeAll()并不能保证以原子方式执行。ConcurrentSkipListSet 是能使用空元素的，即NULL

请自行编写代码验证线程安全性

* **HashMap、TreeMap → ConcurrentHashMap、ConcurrentSkipListMap**

  ConcurrentHashMap不运行空值，ConcurrentHashMap对读读操作进行了大量的优化，具有特别高的并发性。

  ConcurrentSkipListMap基于SkipList这种跳表的结构实现的

ConcurrentHashMap与ConcurrentSkipListMap对比

根据实验，4个线程，1.6万数据的情况下，ConcurrentHashMap的存取速度是ConcurrentSkipListMap的4倍左右

ConcurrentSkipListMap的key是有序的

ConcurrentSkipListMap支持更高的并发，存取时间和线程数是几乎没有关系的，即数据量一定的情况下，线程数越多，越能体现出ConcurrentSkipListMap的优势

请自行编写代码验证线程安全性
