ConcurrentHashMap的get(),put(),又是如何实现的?ConcurrentHashMap有哪些问题? ConcurrentHashMap的锁是读锁还是写锁?

put 操作一上来就锁定了整个segment,这当然是为了并发的安全,修改数据是不能并发进行的,必须得有个判断是否超限的语句以确保容量不足时能够 rehash,
而比较难懂的是这句int index = hash & (tab.length - 1),原来segment里面才是真正的hashtable,即每个segment是一个传统意义上的hashtable, 从两者的结构就可以看出区别,这里就是找出需要的entry在table的哪一个位置,之后得到的entry就是这个链的第一个节点,如果e!=null,说明找到了,这是就要替换节点的值(onlyIfAbsent == false),否则,我们需要new一个entry,它的后继是first,而让tab[index]指向它,什么意思呢?实际上就是将这个新entry 插入到链头,剩下的就非常容易理解了。

get 方法(请注意,这里分析的方法都是针对桶的,因为ConcurrentHashMap的最大改进就是将粒度细化到了桶上),首先判断了当前桶的数据个数是 否为0,为0自然不可能get到什么,只有返回null,这样做避免了不必要的搜索,也用最小的代价避免出错。然后得到头节点(方法将在下面涉及)之后就 是根据hash和key逐个判断是否是指定的值,如果是并且值非空就说明找到了,直接返回;
程序非常简单,但有一个令人困惑的地方,这句return readValueUnderLock(e)到底是用来干什么的呢?研究它的代码,在锁定之后返回一个值。但这里已经有一句V v = e.value得到了节点的值,这句return readValueUnderLock(e)是否多此一举?
事实上,这里完全是为了并发考虑的,这里当v为空时,可能是一个线程正在改变节点,而之前的 get操作都未进行锁定,根据bernstein条件,读后写或写后读都会引起数据的不一致,所以这里要对这个e重新上锁再读一遍,以保证得到的是正确值,
这里不得不佩服Doug Lea思维的严密性。整个get操作只有很少的情况会锁定,相对于之前的Hashtable,并发是不可避免的啊!

ConcurrentHashmap只能保证自身数据在多线程的环境下不被破坏,而并不能保证业务逻辑的正确性。

ConcurrentHashMap的锁是读锁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ConcurrentHashMap 是 Java 中的一个线程安全的哈希表实现,它提供了更好的写并发能力,并降低了对读一致性的要求。ConcurrentHashMap实现原理如下: 1. ConcurrentHashMap 使用了数组+链表+红黑树的数据结构来存储键值对。数组的每个元素称为桶(bucket),每个桶可以存储多个键值对。 2. ConcurrentHashMap 使用哈希算法来确定键值对在数组中的位置。当插入或查找键值对时,首先根据键的哈希值计算出数组中的索引,然后在该索引处的桶中进行操作。 3. 当多个线程同时访问 ConcurrentHashMap 时,每个线程会被分配到不同的段(segment)上。每个段相当于一个独立的小的哈希表,它们之间没有竞争。这样可以提高并发性能。 4. 在 JDK 1.7 中,ConcurrentHashMap 使用了分段(segment lock)来保证线程安全。每个段都有自己的,不同的线程可以同时访问不同的段,从而提高并发性能。 5. 在 JDK 1.8 中,ConcurrentHashMap实现参考了 HashMap实现,采用了数组+链表+红黑树的方式,并且使用了 CAS (Compare and Swap) 操作来保证线程安全。这样可以减少的粒度,提高并发性能。 6. 当多个线程同时修改 ConcurrentHashMap 时,会根据需要对桶进行扩容或者收缩,以保证并发性能和空间利用率。 下面是一个示例代码,演示了如何使用 ConcurrentHashMap: ```java import java.util.concurrent.ConcurrentHashMap; public class ConcurrentHashMapExample { public static void main(String[] args) { ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); // 添加键值对 map.put("apple", 1); map.put("banana", 2); map.put("orange", 3); // 获取键对应的值 int value = map.get("banana"); System.out.println("Value of 'banana': " + value); // 输出:Value of 'banana': 2 // 删除键值对 map.remove("orange"); // 判断键是否存在 boolean containsKey = map.containsKey("orange"); System.out.println("Contains 'orange': " + containsKey); // 输出:Contains 'orange': false } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值