面试题答案
一键面试可能出现的问题
- 线程安全问题:
LinkedHashMap
本身不是线程安全的,在高并发环境下,多个线程同时进行读/写操作,可能会导致数据不一致、ConcurrentModificationException
等异常。 - 性能问题:由于需要保证访问顺序,每次访问元素时都可能涉及到内部链表结构的调整,如果没有合理的并发控制,可能会导致频繁的锁竞争,影响性能。
使用Java并发工具类优化和解决
- 使用
ConcurrentHashMap
和LinkedList
模拟:ConcurrentHashMap
提供线程安全的键值对存储。LinkedList
用于维护访问顺序。
- 使用
ConcurrentLinkedHashMap
:这是Guava
库中的一个类,它结合了ConcurrentHashMap
的线程安全性和LinkedHashMap
的访问顺序特性。
代码示例
使用ConcurrentHashMap
和LinkedList
模拟
import java.util.ConcurrentModificationException;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentLinkedHashMap<K, V> {
private final Map<K, V> map;
private final LinkedList<K> list;
private final int capacity;
public ConcurrentLinkedHashMap(int capacity) {
this.map = new ConcurrentHashMap<>();
this.list = new LinkedList<>();
this.capacity = capacity;
}
public V get(K key) {
V value = map.get(key);
if (value != null) {
synchronized (list) {
list.remove(key);
list.addLast(key);
}
}
return value;
}
public void put(K key, V value) {
if (map.size() >= capacity) {
K oldestKey;
synchronized (list) {
oldestKey = list.removeFirst();
}
map.remove(oldestKey);
}
map.put(key, value);
synchronized (list) {
list.addLast(key);
}
}
public static void main(String[] args) {
ConcurrentLinkedHashMap<Integer, Integer> map = new ConcurrentLinkedHashMap<>(3);
map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
System.out.println(map.get(2));
map.put(4, 4);
System.out.println(map.get(1));
}
}
使用Guava
的ConcurrentLinkedHashMap
首先需要在pom.xml
中添加Guava
依赖:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
然后是代码示例:
import com.google.common.cache.ConcurrentLinkedHashMap;
import com.google.common.cache.RemovalNotification;
public class GuavaConcurrentLinkedHashMapExample {
public static void main(String[] args) {
ConcurrentLinkedHashMap<Integer, Integer> map = ConcurrentLinkedHashMap
.newBuilder()
.maximumWeight(3)
.weightedValue((k, v) -> 1)
.removalListener((RemovalNotification<Integer, Integer> notification) ->
System.out.println("Removed: " + notification.getKey() + "=" + notification.getValue()))
.build();
map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
System.out.println(map.get(2));
map.put(4, 4);
System.out.println(map.get(1));
}
}