mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
8280041: Retry loop issues in java.io.ClassCache
Co-authored-by: Peter Levart <plevart@openjdk.org> Reviewed-by: rkennke, rriggs, plevart
This commit is contained in:
parent
cbe8395ace
commit
cebaad1c94
5 changed files with 202 additions and 12 deletions
|
@ -28,6 +28,7 @@ package java.io;
|
|||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.Objects;
|
||||
|
||||
// Maps Class instances to values of type T. Under memory pressure, the
|
||||
// mapping is released (under soft references GC policy) and would be
|
||||
|
@ -38,19 +39,29 @@ abstract class ClassCache<T> {
|
|||
|
||||
private static class CacheRef<T> extends SoftReference<T> {
|
||||
private final Class<?> type;
|
||||
private T strongReferent;
|
||||
|
||||
CacheRef(T referent, ReferenceQueue<T> queue, Class<?> type) {
|
||||
super(referent, queue);
|
||||
this.type = type;
|
||||
this.strongReferent = referent;
|
||||
}
|
||||
|
||||
Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
T getStrong() {
|
||||
return strongReferent;
|
||||
}
|
||||
|
||||
void clearStrong() {
|
||||
strongReferent = null;
|
||||
}
|
||||
}
|
||||
|
||||
private final ReferenceQueue<T> queue;
|
||||
private final ClassValue<SoftReference<T>> map;
|
||||
private final ClassValue<CacheRef<T>> map;
|
||||
|
||||
protected abstract T computeValue(Class<?> cl);
|
||||
|
||||
|
@ -58,23 +69,41 @@ abstract class ClassCache<T> {
|
|||
queue = new ReferenceQueue<>();
|
||||
map = new ClassValue<>() {
|
||||
@Override
|
||||
protected SoftReference<T> computeValue(Class<?> type) {
|
||||
return new CacheRef<>(ClassCache.this.computeValue(type), queue, type);
|
||||
protected CacheRef<T> computeValue(Class<?> type) {
|
||||
T v = ClassCache.this.computeValue(type);
|
||||
Objects.requireNonNull(v);
|
||||
return new CacheRef<>(v, queue, type);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
T get(Class<?> cl) {
|
||||
processQueue();
|
||||
T val;
|
||||
do {
|
||||
SoftReference<T> ref = map.get(cl);
|
||||
val = ref.get();
|
||||
if (val == null) {
|
||||
map.remove(cl);
|
||||
while (true) {
|
||||
processQueue();
|
||||
|
||||
CacheRef<T> ref = map.get(cl);
|
||||
|
||||
// Case 1: A recently created CacheRef.
|
||||
// We might still have strong referent, and can return it.
|
||||
// This guarantees progress for at least one thread on every CacheRef.
|
||||
// Clear the strong referent before returning to make the cache soft.
|
||||
T strongVal = ref.getStrong();
|
||||
if (strongVal != null) {
|
||||
ref.clearStrong();
|
||||
return strongVal;
|
||||
}
|
||||
} while (val == null);
|
||||
return val;
|
||||
|
||||
// Case 2: Older or recently cleared CacheRef.
|
||||
// Check if its soft referent is still available, and return it.
|
||||
T val = ref.get();
|
||||
if (val != null) {
|
||||
return val;
|
||||
}
|
||||
|
||||
// Case 3: The reference was cleared.
|
||||
// Clear the mapping and retry.
|
||||
map.remove(cl);
|
||||
}
|
||||
}
|
||||
|
||||
private void processQueue() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue