问题
I've implemented an Object cache like so:
// Dictionary with weak keys & values
private Map> cache = new WeakHashMap<>();
private Object checkCache(Object obj) {
// If it's in the cache, returned the cached copy.
if (cache.containsKey(obj)) return cache.get(obj).get();
// Store it in, and return it.
cache.put(obj, new WeakReference<>(obj));
return obj;
}
Picture the following race-condition scenario:
cache.containsKey(obj) returns true
The garbage collector kicks in and reaps the object in the cache.
null is returned.
The questions are:
Can this really happen? AFAIK the GC can kick in at any time.
Can Java GC be disabled for a single method call? synchronized doesn't seem to prevent GC.
Are there any work-arounds?
Thanks in advance!
回答1:
Can this really happen?
Yes.
Can Java GC be disabled for a single method call?
No.
Are there any work-arounds?
Yes: you attempt to retrieve the object from the cache (thereby establishing a strong reference if it's still in the cache), and add to the cache if that reference is null:
WeakReference ref = cache.get(obj);
Object cached = (ref != null) ? ref.get() : null;
if (cached != null) {
return cached;
}
else {
cache.put(obj, new WeakReference(obj));
return obj;
}
You still need to synchronize the method, otherwise you could have two threads updating the cache at the same time (and the resulting update race would be the least of your worries).
回答2:
Are the WeakHashMap and WeakReference required? You can use normal HashMap with normal keys then use a timer thread that will clear the old values in the HashMap. GC is quite unpredictable, so unless you don't mind having null values in your map, I suggest using normal ones.
For concurrency, look in Java 7 Lock interface. It is way better than syncronized methods in terms of control and performance. Check this block about Java Lock Example and Concurrency Lock vs synchronized.
来源:https://stackoverflow.com/questions/24109126/java-racing-against-the-garbage-collector