面试题答案
一键面试1. HashMap
在高并发场景下的性能瓶颈
- 扩容死循环:在高并发环境下,当多个线程同时进行扩容操作时,由于
HashMap
的扩容机制涉及到重新计算哈希值和移动元素,可能会导致链表形成环,进而在获取元素时陷入死循环。 - 数据覆盖:多个线程同时进行
put
操作时,如果计算出的哈希值相同,可能会导致其中一个线程的数据被覆盖。 - 高竞争:
HashMap
内部没有锁机制,当大量线程同时访问时,会出现高竞争情况,导致性能下降。
2. ConcurrentHashMap
解决问题的方式
ConcurrentHashMap
通过分段锁机制解决高并发问题。它将数据分成多个段(Segment),每个段独立加锁,不同段的操作可以并行进行,大大减少了锁的粒度,提高了并发性能。
3. ConcurrentHashMap
底层原理
- JDK1.7:
ConcurrentHashMap
由多个Segment
数组组成,每个Segment
类似于一个小型的HashMap
,包含一个数组和链表。当进行put
操作时,先定位到具体的Segment
,然后对该Segment
加锁进行操作,读操作一般不需要加锁。 - JDK1.8:放弃了分段锁机制,采用数组 + 链表/红黑树结构。引入了
CAS
操作来提高并发性能,同时使用synchronized
关键字对数组的头节点加锁,而不是对整个数组加锁,进一步减小锁粒度。
4. ConcurrentHashMap
分段锁机制
- JDK1.7:每个
Segment
继承自ReentrantLock
,在进行写操作(如put
)时,先通过哈希算法定位到对应的Segment
,然后获取该Segment
的锁,操作完成后释放锁。读操作一般不需要加锁,因为volatile
修饰了数组元素,保证可见性。 - JDK1.8:虽然不再有明确的分段锁概念,但在写操作时,对数组头节点加
synchronized
锁,读操作通过volatile
保证数据可见性。并且利用CAS
操作实现无锁化更新部分数据,提高并发性能。
5. ConcurrentHashMap
相比HashMap
在高并发读写操作上的优势
- 高并发写入:
ConcurrentHashMap
的分段锁机制(JDK1.7)或减小锁粒度(JDK1.8)使得多个线程可以同时对不同部分的数据进行写入操作,而HashMap
在高并发写入时会出现数据覆盖和高竞争问题。 - 高并发读取:
ConcurrentHashMap
读操作一般不需要加锁(JDK1.7)或利用volatile
和CAS
保证可见性和无锁化读取(JDK1.8),读取性能更高。而HashMap
在高并发环境下,由于没有锁机制,可能会读到脏数据。
6. 代码示例
以下是在实际项目中使用ConcurrentHashMap
优化Map
使用的示例:
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ConcurrentHashMapExample {
private static final int THREADS = 10;
private static final int ITERATIONS = 1000;
private static final ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(THREADS);
for (int i = 0; i < THREADS; i++) {
executorService.submit(() -> {
for (int j = 0; j < ITERATIONS; j++) {
map.put(j, j);
}
});
}
executorService.shutdown();
while (!executorService.isTerminated()) {
// 等待所有线程执行完毕
}
System.out.println("Map size: " + map.size());
}
}
在上述代码中,多个线程同时向ConcurrentHashMap
中插入数据,由于ConcurrentHashMap
的设计,这种高并发操作能够高效且安全地执行。如果使用HashMap
,则可能会出现数据覆盖等问题。通过使用ConcurrentHashMap
,在高并发场景下能够显著提高Map
的读写性能。