ConcurrentHashMap 做过什么改进?HashMap 死锁

HashMap是JAVA中最常见的键值对存储对象,但是存在线程安全问题,如果有多个线程同时操作HashMap对象,有可能出现锁问题。早期解决这个问题是使用HashTable,后来又推出性能更高的ConcurrentHashMap,可以支持16个线程执行并发写操作及任意数量线程的读操作; HashTable和ConcurrentHashMap都是线程安全的类。

与Hashtable不同的是,在jdk1.7中ConcurrentHashMap使用的是分段锁技术,将ConcurrentHashMap容器的数据分段存储,每一段数据分配一个Segment(可重入锁),当线程占用一个Segment时,其他线程可以访问其他段的数据.(每个segment都是一个锁). 与hashtable相比,这么设计的目的是对于put, remove等操作,可以减少并发冲突,对不属于同一个片段的节点可以并发操作,大大提高了性能;

ConcurrentHashMap在jdk1.8中做了两方面的改进,改进一:取消segments字段,直接采用transient volatile HashEntry<K,V>[] table保存数据,采用table数组元素作为锁,从而实现了对每一行数据进行加锁,进一步减少并发冲突的概率。改进二:将原先table数组+单向链表的数据结构,变更为table数组+单向链表+红黑树的结构。对于hash表来说,最核心的能力在于将key hash之后能均匀的分布在数组中。如果hash之后散列的很均匀,那么table数组中的每个队列长度主要为0或者1。但实际情况并非总是如此理想,虽然ConcurrentHashMap类默认的加载因子为0.75,但是在数据量过大或者运气不佳的情况下,还是会存在一些队列长度过长的情况,如果还是采用单向列表方式,那么查询某个节点的时间复杂度为O(n);因此,对于个数超过8(默认值)的列表,jdk1.8中采用了红黑树的结构,那么查询的时间复杂度可以降低到O(logN),以此改进性能。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ConcurrentHashMapJava 中的一个线程安全的哈希映射实现,它是在 HashMap 基础上进行了并发性的优化。它的主要实现原理包括: 1. 分段锁(Segmented Locking):将整个哈希表划分为多个独立的段(Segment),每个段有自己的锁。这样,在对特定键值操作时,只需要锁定对应的那段数据,而不是整个 Map,大大提高了并发性能。 2. 并行化查找和插入:当多个线程同时访问时,它们可以在不同段中并行进行查找或插入操作。ConcurrentHashMap 提供了 `putIfAbsent`、`replace()` 等方法的无锁版本(CAS),用于原子操作。 3. 冗余探测(Redundant Reads Detection):对于读取操作,如果一个线程看到的数据后来被其他线程更新了,ConcurrentHashMap 会检测到这种“冗余读”,并且能够正确地返回最新的值。 4. 锁升级与降级策略:为了进一步提高性能,当多个线程竞争同一段的锁时,可能会经历从轻量级锁(LockSupport.parkNanos 或 park/unpark)到重量级锁再到无锁 CAS 的过程,这被称为锁的升级与降级。 5. 非阻塞删除:删除操作相对复杂,因为它涉及到迁移元素。ConcurrentHashMap 使用了一种称为 "Split-Brain Operation"(SBO)的方法,即预计算删除后的影响,然后异步完成实际删除。 相关问题-- 1. ConcurrentHashMap 如何处理多线程竞争? 2. 在高并发情况下,ConcurrentHashMap 如何避免死锁? 3. 删除操作在 ConcurrentHashMap 中是如何实现的?

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值