Java 非线程安全的HashMap如何在四线程中利用

Java 非线程安全的HashMap怎样在三十二线程中行使

 

HashMap
是非线程安全的。在多线程条件下,不难造成死循环,具体表现为CPU使用率100%。由此三十二线程环境下保障HashMap 的线程安全性,紧要有如下二种艺术:

  1. 使用 java.util.Hashtable 类,此类是线程安全的。
  2. 接纳 java.util.concurrent.ConcurrentHashMap,此类是线程安全的。
  3. 动用 java.util.Collections.synchronizedMap() 方法包装 HashMap
    object,获得线程安全的Map,并在此Map上举行操作。
  4. 自己在先后的严重性代码段加锁,保险多线程安全(不引进)

 

接下去分析上边列举的三种艺术已毕产出安全的 HashMap 的原理:

(一)java.util.Hashtable类:

查阅该类的源码

public synchronized V get(Object key) {  
    …… //具体的实现省略,请参考 jdk实现  
}  

public synchronized V put(K key, V value) {  
    …… //具体的实现省略,请参考 jdk实现  
}  

public synchronized V remove(Object key) {  
    …… //具体的实现省略,请参考 jdk实现  
}  

     上边是 Hashtable 类提供的多少个重点方法,包括 get(),put(),remove()
等。注意到每个方法本身都是 synchronized
的,不会现出五个线程同时对数据开展操作的动静,因而保险了线程安全性,可是也大大的下降了实践效用
。因而是不推荐的。

 

(二)使用 java.util.concurrent.ConcurrentHashMap 类:

该类是 HashMap 的线程安全版,与 Hashtable 相比较, ConcurrentHashMap
不仅有限扶助了拜访的线程安全性,而且在功用上有较大的滋长。

ConcurrentHashMap的数据结构如下:

图片 1

可以见见,绝对 HashMap 和 Hashtable, ConcurrentHashMap 增添了Segment
层,每个Segment 原理上同一一个 Hashtable,
ConcurrentHashMap 等同于一个 Segment 的数组。上边是 ConcurrentHashMap 的
put 和 get 方法:

final Segment<K,V> segmentFor(int hash) {  
    return segments[(hash >>> segmentShift) & segmentMask];  
}  

public V put(K key, V value) {  
    if (value == null)  
        throw new NullPointerException();  
    int hash = hash(key.hashCode());  
    return segmentFor(hash).put(key, hash, value, false);  
}  

public V get(Object key) {  
    int hash = hash(key.hashCode());  
    return segmentFor(hash).get(key, hash);  
}  

向 ConcurrentHashMap 中插入数据(put) 或者
读取多少(get),首先都要将相应的 Key 映射到相应的
Segment,所以不要锁定任何类, 只要对单个的 Segment
操作举办上锁操作就可以了
。理论上一旦有 n 个
Segment,那么最多可以同时帮衬 n
个线程的产出访问,从而大大提升了出现访问的效用。