ConcurrentHashMap

来源:互联网 发布:asp.net源码 网络 编辑:程序博客网 时间:2024/05/21 07:59

1 map的分类

(1)非线程安全的map:
    HashMap
(2)线程安全的map:
    HashTable   Collections.synchronizedMap(new HashMap<K, V>())   ConcurrentHashMap

2 各个map的比较

(1)HashMap:非线程安全的,适用于单线程环境,因为不存在锁和阻塞,所以效率较高
(2)HashTable:线程安全的,使用synchronized关键字修饰方法,实现了线程安全。单线程环境下,建议使用HashMap,因为锁的管理也需要开销。
(3)Collections.synchronizedMap(map):线程安全的,使用Collections里面的静态方法将非线程安全的map封装成线程安全的map。效率和应用场景方面与HashTable相同。
(4)ConcurrentHashMap:一个专用于高并发的map。使用了分段锁机制,减小锁粒度,因此提高了并发度。

3 ConcurrentHashMap浅析

3.1 底层存储结构图


3.2 分段锁

    ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。

    ConcurrentHashMap是专门为线程并发而设计的,它的get操作是无锁的,它的put操作只在对应的segment上加锁。因此,它的整体性能优于同步的HashMap(对整个table加锁)。
    默认情况下,ConcurrentHashMap拥有16个段,因此,足够幸运的话,可以同时接受16个线程同时put(插入到不同段中)。

3.3 弱一致性问题

    由于get方法,并没有加锁,因此肯定会存在一致性的问题。get方法并没有加锁,因此也不会和put方法冲突,当多个线程同时操作该map时,有的线程get,有的线程put,因为我们并不确定put方法执行完了没(可能只执行了一部分语句,后面真正改内存的语句还没有执行),所以get不一定能够得到最新值(put还没写进去,叫最新值也不是很妥当)。但是,一旦put操作执行完,那么get一定可以感知到最新值,因为Node的val和next字段都是volatile的:

 static class Node<K,V> implements Map.Entry<K,V> {        final int hash;        final K key;        volatile V val;        volatile Node<K,V> next;}

  同理,很多全局方法都存在弱一致性问题,比如size等。

   ConcurrentHashMap的弱一致性主要是为了提升效率,是一致性与效率之间的一种权衡。要成为强一致性,就得到处使用锁,甚至是全局锁。

  上面仅是个人的一点浅见,有不妥之处欢迎指出。


0 0
原创粉丝点击