1、典型回答
ConcurrentHashMap 在不同JDK 版本中,保证线程安全的手段是不同的,它主要分为以下两种情况:
- JDK 1.7 之前(包含JDK 1.7),ConcurrentHashMap 主要是通过分段锁 (Segment Lock) 来保证线程安全的。
- 而在JDK 1.8 之后(包含JDK 1.8) ,使用了粒度更小锁,通过在数组的头节点加锁来保证线程安全的,并且加锁的手段也进行了优化,它使用的是 CAS + volatile 或 synchronized 来保证线程安全的。
2、全面剖析
concurrentHashMap 在早期版本中(JDK 1.7 之前,包含JDK 1.7)是通过悲观锁 Lock 添加分段锁来保证线程安全的,而到了之后版本中,是通过粒度更小的在数组头节点加锁(悲观锁 synchronized 或者是乐观锁CAS+volatile)的方式来保证线程安全的
那么问题来了,什么是分段锁? 请参考:什么是分段锁?-CSDN博客
分段锁的实现如下图所示:
高版本头节点加锁示意图如下:
3、知识扩展
什么是悲观锁和乐观锁? 它们有什么区别?
悲观锁和乐观锁是并发编程中常用的两种锁机制(或者说两种锁策略或者是两种实现锁的思想)
它们的区别如下:
- 悲观锁(Pessimistic Locking):悲观锁假设会发生竞争,因此在访问共享资源前会获取锁,以防止其他线程对该资源的修改。悲观锁在操作期间会将共享资源锁定,其他线程无法操作,直到锁被释放。!典型的悲观锁实现包括 synchronized 关键字和 ReentrantLock。
- 乐观锁(Optimistic Locking):乐观锁假设不会发生竞争,因此在访问共享资源时不会加锁,而是在更新资源时检查是否有其他线程同时更新,并通过版本号等方式进行验证。如果验证通过,则更新资源,否则重新尝试。乐观锁适用于并发冲突相对较少的情况,能够提高并发性能。典型的乐观锁实现包括 CAS(Compare andSwap) 操作和版本号机制。
它们的区别主要体现在以下几点:
- 加锁机制:悲观锁在访问共享资源前会获取锁,而乐观锁在访问共享资源时不会加锁
- 锁状态:悲观锁将共享资源锁定,其他线程无法操作,而乐观锁不会锁定资源,允许其他线程同时访问。
- 并发性能:乐观锁适用于并发冲突较少的场景,可以提供更好的并发性能,而悲观锁则适用于竞争较激烈的场景,保证数据的一致性和安全性。