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
个线程的出现访问,从而大大提高了出现访问的频率。

 

相关文章