java - WeakHashMap 和 ReentrantReadWriteLock
问题描述
我使用 WeakHashMap 和 ReentrantReadWriteLock 实现了一个缓存,我的代码是这样的:
class Demo<T, K> {
private final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();
private final Map<T, K> CACHE = new WeakHashMap<>();
public K get(T t) {
ReentrantReadWriteLock.ReadLock readLock = LOCK.readLock();
ReentrantReadWriteLock.WriteLock writeLock = LOCK.writeLock();
readLock.lock();
if(CACHE.containsKey(t)){
//-- question point --
K result = CACHE.get(t);
readLock.unlock();
return result;
}
readLock.unlock();
K result = // find from db;
writeLock.lock();
CACHE.put(t,result);
writeLock.unlock();
return result;
}
}
我的问题是,如果 gc 在读锁之后if(CACHE.containsKey(t))
但之前执行K result = CACHE.get(t);
并导致这if(CACHE.containsKey(t))
是真的,但K result = CACHE.get(t);
会变为空。
解决方案
您ReentrantReadWriteLock
无法控制WeakHashMap
垃圾收集器的行为。
WeakHashMap
状态类 javadoc
类的行为
WeakHashMap
部分取决于垃圾收集器的行为,因此一些熟悉的(尽管不是必需的)Map
不变量不适用于此类。因为垃圾收集器可能随时丢弃键,aWeakHashMap
可能表现得好像一个未知线程正在默默地删除条目。特别是,即使你在一个WeakHashMap
实例上同步并且不调用它的任何 mutator 方法,size 方法也有可能随着时间的推移返回较小的值,isEmpty
方法返回false
然后true
,方法containsKey
返回true
并稍后返回false
给定的key,用于get
为给定键返回值但稍后返回null
的方法put
方法返回null
和 remove 方法返回false
以前出现在映射中的键,并连续检查键集、值集合和条目集以产生连续较少数量的元素。
换句话说,是的,如果垃圾收集器在两个调用之间起作用(并且您没有其他对相应键的强引用),则您的containsKey
调用可能会返回true
,get
随后的调用可能会返回。false
您可以使用类似的小程序验证此行为
public class Example {
public static void main(String[] args) throws Exception {
WeakHashMap<Example, Integer> CACHE = new WeakHashMap<>();
CACHE.put(new Example(), 2);
if (CACHE.containsKey(new Example())) {
System.gc();
System.out.println("missing? " + CACHE.get(new Example()));
}
}
@Override
public int hashCode() {
return 42;
}
@Override
public boolean equals(Object obj) {
return true;
}
}
哪个打印
missing? null
推荐阅读
- c++ - Vtk 热图:雷达数据的科学可视化:为 vtkPlaneSource 更新 vtkFloatArray
- xpath - 使用 XPATH 获取元素
- javascript - 如何在antdesign中的下拉事件“触发”上应用mixpanel
- java - 如何对 OpenJDK 进行更改并运行程序?
- python - 用python在sql server中插入数据
- c# - 我可以使用 Ocelot 将 POST http 请求重新路由到 GET http 请求吗?
- wordpress - 如何在 wordpress 插件中部署反应图像?
- android - ViewGroup 将所有项目宽度设置为孩子要求的最大值
- java - logback 文件名格式,包括时间格式
- azure - 将 VM 规模集附加到应用程序网关的后端池