面试题答案
一键面试1. ConcurrentHashMap线程安全实现机制
- 分段锁机制(早期版本 - Java 7及以前)
- 原理:将整个哈希表分成多个段(Segment),每个段类似一个独立的哈希表。当进行写操作(put等)时,只需锁定当前操作涉及的段,而不是整个哈希表。读操作(get等)通常不需要加锁,因为使用了volatile关键字修饰内部数据结构,保证可见性。
- 示例:假设有16个段,不同线程对不同段进行put操作时,不会相互阻塞,提高了并发度。
- CAS + synchronized (Java 8及以后)
- 原理:取消了分段锁,采用Node数组存储数据。在插入新节点时,首先使用CAS操作尝试插入,如果失败,则使用synchronized关键字对当前桶(bin)进行同步控制。
- 示例:当多个线程同时向同一个桶插入数据时,CAS操作失败,后续线程会进入synchronized块进行顺序插入,保证线程安全。
2. 与传统HashMap在实现上的主要区别
- 线程安全
- HashMap:非线程安全,在多线程环境下,多个线程同时进行put、get等操作可能会导致数据不一致、死循环等问题。
- ConcurrentHashMap:通过上述的分段锁(早期)或CAS + synchronized(Java 8及以后)机制保证线程安全,适合多线程环境。
- 数据结构
- HashMap:在Java 8以前,由数组 + 链表组成;Java 8及以后,在链表长度大于8且数组长度大于64时,链表会转换为红黑树,以提高查找效率。
- ConcurrentHashMap:Java 8及以后,基本数据结构与HashMap类似,也是数组 + 链表 + 红黑树,但在实现上增加了线程安全控制机制。
- 扩容机制
- HashMap:扩容时,需要重新计算每个元素的哈希值并重新插入到新的数组中,这个过程是单线程的,在多线程环境下可能会出现问题。
- ConcurrentHashMap:采用更复杂的并发扩容机制,在扩容时,允许多个线程同时进行部分数据的迁移,提高了扩容效率,同时保证线程安全。
3. 在高并发场景下的性能优势
- 减少锁竞争:早期的分段锁机制和Java 8的CAS + synchronized机制,都有效减少了锁的粒度,降低了锁竞争的可能性,从而提高了并发性能。例如在多线程写入时,不同线程可以操作不同的段或桶,而无需竞争同一把大锁。
- 高效的读操作:读操作通常不需要加锁(除了一些特殊情况,如size操作等),通过volatile关键字保证数据可见性,使得读操作在高并发场景下性能很高。例如,多个线程可以同时进行读操作,而不会相互阻塞。
- 并发扩容:在高并发写入导致需要扩容时,ConcurrentHashMap的并发扩容机制允许多个线程同时参与数据迁移,相比HashMap单线程扩容,大大缩短了扩容时间,提高了系统的整体性能和响应速度。