对ConcurrentHashMap的理解

ConcurrentHashMap比HashMap并发好,比HashTable效率高,因为HashTable在对数据操作的时候都会上锁。

ConcurrentHashMap 在 JDK1.7 和 JDK1.8 的实现方式是不同的。

JDK1.7

JDK1.7 中的 ConcurrentHashMap 是segment+数组+链表的结构,即 ConcurrentHashMap 把哈希桶数组切分成小数组(Segment ),每个小数组有 n 个 HashEntry 组成。

原理上来说,ConcurrentHashMap 采用了分段锁技术,其中 Segment 继承于 ReentrantLock。

不会像 HashTable 那样不管是 put 还是 get 操作都需要做同步处理,理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数量)的线程并发。

每当一个线程占用锁访问一个 Segment 时,不会影响到其他的 Segment。

就是说如果容量大小是16他的并发度就是16,可以同时允许16个线程操作16个Segment而且还是线程安全的。

JDK1.8

在数据结构上, JDK1.8 中的ConcurrentHashMap 选择了与 HashMap 相同的数组+链表+红黑树结构;在锁的实现上,抛弃了原有的 Segment 分段锁,采用CAS+synchronized实现更加细粒度的锁,如果多个线程访问的链表头结点不同,则不会冲突。

ConcurrentHashMap的put方法的执行逻辑

JDK1.7

  1. 尝试自旋获取锁。
  2. 如果重试的次数达到了上限则改为阻塞锁获取,保证能获取成功。

JDK1.8

  1. 根据key计算出hashcode。
  2. 判断是否需要进行初始化。
  3. 定位到Node,拿到首节点,判断首节点:
  •         如果为null,则通过CAS的方式尝试添加,失败则自旋保证成功。
  •         如果hashcode == MOVED == -1,说明其他线程在扩容,参与一起扩容。
  •         如果都不满足,则利用synchronized锁写入数据。

      4. 如果数量大于阈值则要转换为红黑树。

ConcurrentHashMap的get方法的执行逻辑

 JDK1.7

将key通过hash之后定位到具体的segment,再通过一次hash定位到具体的元素上。、

由于HashEntry中的value属性是用volatile关键词修饰的,保证了内存可见性,所以每次获取时都是新值,整个过程不用加锁。

JDK1.8

  1. 根据计算出来的hashcode寻址,如果就在桶上那么直接返回值。
  2. 如果是红黑树那就按照树的方式获取值。
  3. 都不满足那就按照链表的方式遍历获取值。

为什么Hashtable和ConcurrentHashMap是不允许键或值为 null 的,HashMap 的键值则都可以为 null? 

ConcurrentHashmap和Hashtable都是支持并发的,这样会有一个问题,当你通过get(k)获取对应的value时,如果获取到的是null时,你无法判断,它是put(k,v)的时候value为null,还是这个key从来没有做过映射。HashMap是非并发的,可以通过contains(key)来做这个判断。而支持并发的Map在调用contains(key)和get(key),Map可能已经不同了。

但是HashMap却做了特殊处理。 

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

多线程下安全的操作 map还有其他方法吗?

还可以使用Collections.synchronizedMap方法,对方法进行加同步锁。

如果传入的是 HashMap 对象,其实也是对 HashMap 做的方法做了一层包装,里面使用对象锁来保证多线程场景下,线程安全,本质也是对 HashMap 进行全表锁。

在竞争激烈的多线程环境下性能依然也非常差,不推荐使用! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值