WeakHashMap 和 ReentrantReadWriteLock
WeakHashMap and 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;
}
}
我的问题是,在 if(CACHE.containsKey(t))
之后但在 K result = CACHE.get(t);
之前执行 gc 是否会发生读取锁定并导致 if(CACHE.containsKey(t))
为真但 K result = CACHE.get(t);
得到空。
那么您的代码将 return 为空。
如果这不是您想要的,只需执行 get() 调用并检查是否得到非空结果。如果您担心 returning null,那么像您一样在此处调用 containsKey() 没有任何好处。
您的 ReentrantReadWriteLock
无法控制 WeakHashMap
关于垃圾收集器的行为。
WeakHashMap
状态的 class javadoc
The behavior of the WeakHashMap
class depends in part upon the actions
of the garbage collector, so several familiar (though not required)
Map
invariants do not hold for this class. Because the garbage
collector may discard keys at any time, a WeakHashMap
may behave as
though an unknown thread is silently removing entries. In particular,
even if you synchronize on a WeakHashMap
instance and invoke none of
its mutator methods, it is possible for the size method to return
smaller values over time, for the isEmpty
method to return false
and
then true
, for the containsKey
method to return true
and later false
for a given key, for the get
method to return a value for a given key
but later return null
, for the put
method to return null
and the
remove method to return false
for a key that previously appeared to be
in the map, and for successive examinations of the key set, the value
collection, and the entry set to yield successively smaller numbers of
elements.
换句话说,是的,您的 containsKey
调用 return true
和 return [=20] 之后的 get
是可能的=],如果垃圾收集器在两次调用之间起作用(并且您没有对相应键的其他强引用)。
您可以使用像
这样的小程序来验证此行为
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
我使用 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;
}
}
我的问题是,在 if(CACHE.containsKey(t))
之后但在 K result = CACHE.get(t);
之前执行 gc 是否会发生读取锁定并导致 if(CACHE.containsKey(t))
为真但 K result = CACHE.get(t);
得到空。
那么您的代码将 return 为空。
如果这不是您想要的,只需执行 get() 调用并检查是否得到非空结果。如果您担心 returning null,那么像您一样在此处调用 containsKey() 没有任何好处。
您的 ReentrantReadWriteLock
无法控制 WeakHashMap
关于垃圾收集器的行为。
WeakHashMap
状态的 class javadoc
The behavior of the
WeakHashMap
class depends in part upon the actions of the garbage collector, so several familiar (though not required)Map
invariants do not hold for this class. Because the garbage collector may discard keys at any time, aWeakHashMap
may behave as though an unknown thread is silently removing entries. In particular, even if you synchronize on aWeakHashMap
instance and invoke none of its mutator methods, it is possible for the size method to return smaller values over time, for theisEmpty
method to returnfalse
and thentrue
, for thecontainsKey
method to returntrue
and laterfalse
for a given key, for theget
method to return a value for a given key but later returnnull
, for theput
method to returnnull
and the remove method to returnfalse
for a key that previously appeared to be in the map, and for successive examinations of the key set, the value collection, and the entry set to yield successively smaller numbers of elements.
换句话说,是的,您的 containsKey
调用 return true
和 return [=20] 之后的 get
是可能的=],如果垃圾收集器在两次调用之间起作用(并且您没有对相应键的其他强引用)。
您可以使用像
这样的小程序来验证此行为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