如何安全的使用HashMap

为什么HashMap是不安全的

HashMap的线程不安全是由于它本身的机制造成的。HashMap的存储结构是由数组+单链表组成的。

transient Node[] table; 
static class Node implements Map.Entry {
        final int hash;
        final K key;
        V value;
        Node next;
}

HashMap的内存存储使用了Node,Node中有一个属性为next,相当于是一个链表,所有hash值相同的key会存储到一个链表里。
PS:在Java 8中如果hash值相同的key数量大于指定值(默认是8)时使用平衡树来代替链表,这会将get()方法的性能从O(n)提高到O(logn)。
HashMap的Node数组默认大小为16,默认负载因子为0.75。如果当前数据长度大于当前最大容量*负载因子时,就会执行扩容resize(),扩容大小为之前的2倍。
HashMap在并发执行put操作时会引起死循环,导致CPU利用率接近100%。因为多线程会导致HashMap的Node链表形成环形数据结构,一旦形成环形数据结构,Node的next节点永远不为空,就会在获取Node时产生死循环。

如何使用线程安全的HashMap

Hashtable

Hashtable内部使用了synchronized来保证线程安全,效率较低。

ConcurrentHashMap

ConcurrentHashMap引入segment的概念。Segment在实现上继承了ReentrantLock。
Java8中摒弃了segment了,使用CAS的算法。

SynchronizedMap

Collections.getSynchronizedMap()返回一个SynchronizedMap()对象,使用synchronized关键字来保证对Map的操作是多线程安全的。

效率

ConcurrentHashMap > (SynchronizedMap or HashTable)

你可能感兴趣的:(如何安全的使用HashMap)