ConcurrentHashMap使用方法

来源:互联网 发布:冰冰办公软件 编辑:程序博客网 时间:2024/04/28 10:07
ConcurrentHashMap是Java 5中支持高并发、高吞吐量的线程安全HashMap实现。在这之前我对ConcurrentHashMap只有一些肤浅的理解,
仅知道它采用了多个锁,大概也足够了。但是在经过一次惨痛的面试经历之后,我觉得必须深入研究它的实现。面试中被问到读是否要加锁,
因为读写会发生冲突,我说必须要加锁,我和面试官也因此发生了冲突,结果可想而知。还是闲话少说,通过仔细阅读源代码,
现在总算理解ConcurrentHashMap实现机制了,其实现之精巧,令人叹服,与大家共享之。


ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。
ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。
 
有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,
操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁,在ConcurrentHashMap内部,段数组是final的,
并且其成员变量实际上也是final的,但是,仅仅是将数组声明为final的并不保证数组成员也是final的,这需要实现上的保证。这可以确保不会出现死锁,
因为获得锁的顺序是固定的。不变性是多线程编程占有很重要的地位,下面还要谈到。
 
Java代码  
/**  * The segments, each of which is a specialized hash table  */  final Segment<K,V>[] segments;   
 
不变(Immutable)和易变(Volatile)
 
ConcurrentHashMap完全允许多个读操作并发进行,读操作并不需要加锁。如果使用传统的技术,
如HashMap中的实现,如果允许可以在hash链的中间添加或删除元素,读操作不加锁将得到不一致的数据。
ConcurrentHashMap实现技术是保证HashEntry几乎是不可变的。


先看看代码吧,模拟1000个并发,每个测试1000次操作,循环测试10轮。分别测试Put和Get操作 

import java.util.Collections;import java.util.HashMap;import java.util.Hashtable;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;/** * 测试HashMap和ConcurrentHashMap的并发性能差别。 *  * @author 老紫竹 JAVA世纪网(java2000.net) *  */public class T {  static final int threads = 1000;  static final int NUMBER = 1000;  public static void main(String[] args) throws Exception {    Map<String, Integer> hashmapSync = Collections        .synchronizedMap(new HashMap<String, Integer>());    Map<String, Integer> concurrentHashMap = new ConcurrentHashMap<String, Integer>();    Map<String, Integer> hashtable = new Hashtable<String, Integer>();    long totalA = 0;    long totalB = 0;    long totalC = 0;    for (int i = 0; i <= 10; i++) {      totalA += testPut(hashmapSync);      totalB += testPut(concurrentHashMap);      totalC += testPut(hashtable);    }    System.out.println("Put time HashMapSync=" + totalA + "ms.");    System.out.println("Put time ConcurrentHashMap=" + totalB + "ms.");    System.out.println("Put time Hashtable=" + totalC + "ms.");    totalA = 0;    totalB = 0;    totalC = 0;    for (int i = 0; i <= 10; i++) {      totalA += testGet(hashmapSync);      totalB += testGet(concurrentHashMap);      totalC += testGet(hashtable);    }    System.out.println("Get time HashMapSync=" + totalA + "ms.");    System.out.println("Get time ConcurrentHashMap=" + totalB + "ms.");    System.out.println("Get time Hashtable=" + totalC + "ms.");  }  public static long testPut(Map<String, Integer> map) throws Exception {    long start = System.currentTimeMillis();    for (int i = 0; i < threads; i++) {      new MapPutThread(map).start();    }    while (MapPutThread.counter > 0) {      Thread.sleep(1);    }    return System.currentTimeMillis() - start;  }  public static long testGet(Map<String, Integer> map) throws Exception {    long start = System.currentTimeMillis();    for (int i = 0; i < threads; i++) {      new MapPutThread(map).start();    }    while (MapPutThread.counter > 0) {      Thread.sleep(1);    }    return System.currentTimeMillis() - start;  }}class MapPutThread extends Thread {  static int counter = 0;  static Object lock = new Object();  private Map<String, Integer> map;  private String key = this.getId() + "";  MapPutThread(Map<String, Integer> map) {    synchronized (lock) {      counter++;    }    this.map = map;  }  public void run() {    for (int i = 1; i <= T.NUMBER; i++) {      map.put(key, i);    }    synchronized (lock) {      counter--;    }  }}class MapGetThread extends Thread {  static int counter = 0;  static Object lock = new Object();  private Map<String, Integer> map;  private String key = this.getId() + "";  MapGetThread(Map<String, Integer> map) {    synchronized (lock) {      counter++;    }    this.map = map;  }  public void run() {    for (int i = 1; i <= T.NUMBER; i++) {      map.get(key);    }    synchronized (lock) {      counter--;    }  }}



运行结果:
Put time HashMapSync=3966ms.
Put time ConcurrentHashMap=1892ms.
Put time Hashtable=3892ms.
Get time HashMapSync=3812ms.
Get time ConcurrentHashMap=1828ms.
Get time Hashtable=3985ms.
原创粉丝点击