WeakKeyConcurrentMap
# 功能介绍
WeakKeyConcurrentMap是Hutool中提供的基于弱引用键的并发Map实现,它结合了ConcurrentHashMap的并发安全特性和弱引用键的自动回收机制。与WeakConcurrentMap不同,WeakKeyConcurrentMap是键使用弱引用,而值使用强引用。当键对象没有其他强引用指向时,JVM进行垃圾回收时会将该键值对自动回收,这使得WeakKeyConcurrentMap非常适合实现对象关联映射,避免内存泄漏。
# 主要特性
- 基于弱引用键实现,键对象没有强引用时自动回收键值对
- 并发安全,支持多线程操作
- 基于ConcurrentHashMap实现,性能优异
- 支持所有Map接口方法
- 支持null值,但不支持null键
- 支持自动清理过期条目
- 线程安全,适合多线程环境使用
- 支持自定义引用队列和清理策略
- 键使用弱引用,值使用强引用
- 键对象没有强引用时,键值对在垃圾回收时自动回收
# 适用场景
- 实现对象关联映射,避免内存泄漏
- 实现事件监听器映射
- 缓存与特定对象关联的数据
- 实现对象到数据的临时映射
- 多线程环境下的对象关联缓存
- 避免因键对象导致内存泄漏的场景
- 实现对象属性缓存
- 任何需要自动回收键值对的Map场景
# 使用示例
# 示例1:基本用法
// 创建WeakKeyConcurrentMap实例
WeakKeyConcurrentMap<Object, String> weakKeyMap = new WeakKeyConcurrentMap<>();
// 创建键对象
Object key1 = new Object();
Object key2 = new Object();
// 添加键值对,键使用弱引用,值使用强引用
weakKeyMap.put(key1, "value1");
weakKeyMap.put(key2, "value2");
// 获取值
String value1 = weakKeyMap.get(key1);
// 输出: value1
// 解除键对象的强引用
key1 = null;
// 手动触发垃圾回收
System.gc();
// 再次获取,键已被回收,返回null
String value2 = weakKeyMap.get(new Object()); // 新对象,与之前的key1不是同一个对象
// 输出: null
// key2仍有强引用,值仍然可以获取
String value3 = weakKeyMap.get(key2);
// 输出: value2
# 示例2:对象关联映射
// 创建WeakKeyConcurrentMap实例,用于关联对象和数据
WeakKeyConcurrentMap<Person, String> personDataMap = new WeakKeyConcurrentMap<>();
// 创建Person对象
Person person1 = new Person("张三", 20);
Person person2 = new Person("李四", 25);
// 关联对象和数据
personDataMap.put(person1, "张三的数据");
personDataMap.put(person2, "李四的数据");
// 获取关联数据
String data1 = personDataMap.get(person1);
// 输出: 张三的数据
// 解除person1的强引用
person1 = null;
// 手动触发垃圾回收
System.gc();
// 再次获取,person1已被回收,返回null
String data2 = personDataMap.get(new Person("张三", 20)); // 新对象,与之前的person1不是同一个对象
// 输出: null
// person2仍有强引用,数据仍然可以获取
String data3 = personDataMap.get(person2);
// 输出: 李四的数据
# 示例3:遍历和清理
// 创建WeakKeyConcurrentMap实例
WeakKeyConcurrentMap<Object, String> weakKeyMap = new WeakKeyConcurrentMap<>();
// 创建键对象
Object key1 = new Object();
Object key2 = new Object();
// 添加键值对
weakKeyMap.put(key1, "value1");
weakKeyMap.put(key2, "value2");
// 遍历Map
weakKeyMap.forEach((key, value) -> {
Console.log(key + "=" + value);
});
// 输出:
// java.lang.Object@...=value1
// java.lang.Object@...=value2
// 解除key1的强引用
key1 = null;
// 手动触发垃圾回收
System.gc();
// 手动清理已回收的条目
int cleanedCount = weakKeyMap.cleanUp();
// 输出: 1(假设key1已被回收)
// 获取Map大小
int size = weakKeyMap.size();
// 输出: 1(只保留key2对应的键值对)
// 清空Map
weakKeyMap.clear();
# 示例4:事件监听器映射
// 创建WeakKeyConcurrentMap实例,用于存储事件监听器
WeakKeyConcurrentMap<EventListener, String> listenerMap = new WeakKeyConcurrentMap<>();
// 创建事件监听器
EventListener listener1 = new EventListener() {
@Override
public void onEvent(Event event) {
Console.log("Listener1 received event: " + event);
}
};
EventListener listener2 = new EventListener() {
@Override
public void onEvent(Event event) {
Console.log("Listener2 received event: " + event);
}
};
// 注册监听器
listenerMap.put(listener1, "listener1");
listenerMap.put(listener2, "listener2");
// 触发事件
Event event = new Event("test");
for (Map.Entry<EventListener, String> entry : listenerMap.entrySet()) {
entry.getKey().onEvent(event);
}
// 解除listener1的强引用
listener1 = null;
// 手动触发垃圾回收
System.gc();
// 再次触发事件,listener1已被回收,只会调用listener2
for (Map.Entry<EventListener, String> entry : listenerMap.entrySet()) {
entry.getKey().onEvent(event);
}
# 注意事项
- WeakKeyConcurrentMap是线程安全的,适合多线程环境使用
- 基于弱引用键实现,键对象没有强引用时自动回收键值对
- 不支持null键,但支持null值
- 性能与ConcurrentHashMap相当,适合大多数场景
- 建议定期调用cleanUp()方法清理已回收的条目,避免内存泄漏
- 弱引用键的回收时机取决于JVM的垃圾回收策略,无法精确控制
- 键对象必须正确实现hashCode()和equals()方法,否则可能导致无法正确获取值
- 适合实现对象关联映射,避免内存泄漏
- 可以通过构造函数自定义引用队列
- 键对象没有强引用时,键值对在下次垃圾回收时被回收
# 方法列表
WeakKeyConcurrentMap实现了ConcurrentMap接口,因此支持所有Map接口方法,主要包括:
| 方法名 | 描述 | 参数 | 返回值 |
|---|---|---|---|
| WeakKeyConcurrentMap() | 创建默认的WeakKeyConcurrentMap | 无 | 无 |
| WeakKeyConcurrentMap(ReferenceQueue | 使用自定义引用队列创建WeakKeyConcurrentMap | queue: 引用队列 | 无 |
| put(K key, V value) | 添加键值对,键使用弱引用,值使用强引用 | key: 键, value: 值 | V |
| get(Object key) | 获取值 | key: 键 | V |
| remove(Object key) | 移除键值对 | key: 键 | V |
| clear() | 清空所有键值对 | 无 | void |
| size() | 获取Map大小(包括已回收但未清理的条目) | 无 | int |
| cleanUp() | 清理已回收的条目 | 无 | int |
| containsKey(Object key) | 判断是否包含指定键 | key: 键 | boolean |
| containsValue(Object value) | 判断是否包含指定值 | value: 值 | boolean |
| keySet() | 获取所有键的集合 | 无 | Set |
| values() | 获取所有值的集合 | 无 | Collection |
| entrySet() | 获取所有键值对的集合 | 无 | Set<Map.Entry<K, V>> |
| forEach(BiConsumer<? super K, ? super V> action) | 遍历所有键值对 | action: 遍历操作 | void |
| replace(K key, V oldValue, V newValue) | 替换键值对(并发安全) | key: 键, oldValue: 旧值, newValue: 新值 | boolean |
| putIfAbsent(K key, V value) | 如果键不存在则添加键值对(并发安全) | key: 键, value: 值 | V |