面试题答案
一键面试使用ConcurrentHashMap在多线程环境下安全实现类似HashMap功能
- 初始化ConcurrentHashMap:
这里创建了一个ConcurrentHashMap<String, Integer> concurrentHashMap = new ConcurrentHashMap<>();
ConcurrentHashMap
实例,键的类型为String
,值的类型为Integer
。 - 添加元素:
concurrentHashMap.put("key1", 1);
put
方法用于向ConcurrentHashMap
中添加键值对。如果键已存在,会更新对应的值。 - 获取元素:
Integer value = concurrentHashMap.get("key1");
get
方法根据键获取对应的值。如果键不存在,返回null
。 - 遍历ConcurrentHashMap:
使用concurrentHashMap.forEach((key, value) -> { System.out.println("Key: " + key + ", Value: " + value); });
forEach
方法对ConcurrentHashMap
进行遍历,执行给定的操作。
ConcurrentHashMap相较于HashMap在并发访问控制方面的优化
- 锁分段技术:
HashMap
在多线程环境下如果不进行额外的同步处理,会出现数据竞争问题。而ConcurrentHashMap
采用锁分段技术。它将整个哈希表分为多个段(Segment),每个段都有自己独立的锁。- 例如,在
JDK 1.7
的ConcurrentHashMap
中,默认有16个段。不同线程对不同段进行操作时,不会相互干扰,从而提高了并发性能。只有在访问同一分段内的数据时才需要竞争锁。
- 读操作几乎无锁:
HashMap
在多线程读操作时,如果没有同步机制,可能读到不一致的数据。ConcurrentHashMap
在JDK 1.8
之后,读操作大多时候不需要加锁。它通过volatile
修饰的数组和链表/红黑树节点来保证可见性。写操作(如put
)时,虽然会对部分数据结构进行修改,但读操作能通过volatile
的特性看到最新的数据,这使得读操作在大多数情况下可以无锁执行,进一步提升了并发性能。
- 支持高并发的写操作:
- 相比
HashMap
在多线程写操作时需要对整个哈希表加锁(如使用synchronized
关键字同步方法或块),导致其他线程无法访问哈希表,ConcurrentHashMap
的锁粒度更细。 - 在
JDK 1.8
中,ConcurrentHashMap
使用CAS
(Compare - and - Swap)操作和synchronized
关键字结合来实现高效的并发写操作。CAS
用于无锁情况下的更新操作,只有在CAS
失败时才使用synchronized
锁,这大大减少了锁竞争,提高了并发写的效率。
- 相比