如何安全的使用HashMap

为什么HashMap是不安全的

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

transient Node<K,V>[] table; 
static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> 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)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容