并发容器
JAVA中常见的并发的容器有HashMap、ConcurrentHashMap、CopyOnWriteArrayList
HashMap
HashMap在并发场景时候存在几个问题:
- get()方法在容器扩容时,获取到的值可能会不正确。因为在扩容时候,hashMap没有保证容器安全性,可能会出现get()方法获取到镜像链表上,而镜像链表此时并没有值的情况
- put()方法可能会造成值消失(这也是map k-v的特性)
- 可见性问题
- 死循环cpu占用100%。多个线程同时扩容时,采用头插法的方式进行插入数据时,会反转散列表的节点以及下属节点之间的关系,从而产生循环节点. 当对这个循环进行遍历时,会产生死循环的情况。
ConcurrentHashMap
ConcurrentHashMap底层是采用CAS+synchronized的方式,来保证并发安全性。
- synchronized保证写操作时资源竞争激烈情况下的安全
- 用CAS机制来保证写操作下轻量级的竞争的安全性。
map中链表红黑树的设计:红黑树在map中属于一种保底,防御性的编程方式。当hash()方法设计良好的时候,散列表中的元素是符合泊松分布,此时很难出现红黑树的情况,可能性为千万分之一,当出现这样的情况时。首先看容量,在考虑hash()方法是否设计良好。8个的限制是基于空间和时间权衡下得出的。
CopyOnWriteArrayList
CopyOnWriteArrayList是线程安全的列表,适合于读多写少的场景,列入内存字典等。
CopyOnWriteArrayList底层是采用ReentrantLock和volatile修饰数组来保证并发的安全性的。
特点:可在迭代器中进行修改列表,当时不会在此次迭代中体现。原因是内部采用双重数组的方式进行扩容,因此迭代器只能读取迭代开始时的元素集合。