Replace ConcurrentHashMap at allLeaks with a thread-safe set (#8467)

Motivation:
allLeaks is to store the DefaultResourceLeak. When we actually use it, the key is DefaultResourceLeak, and the value is actually a meaningless value.
We only care about the keys of allLeaks and don't care about the values. So Set is more in line with this scenario.
Using Set as a container is more consistent with the definition of a container than Map.

Modification:

Replace allLeaks with set. Create a thread-safe set using 'Collections.newSetFromMap(new ConcurrentHashMap<DefaultResourceLeak<?>, Boolean>()).'
This commit is contained in:
时无两丶 2018-11-06 18:21:56 +08:00 committed by Norman Maurer
parent 5954110b9a
commit 28f9136824
1 changed files with 9 additions and 25 deletions

View File

@ -26,8 +26,10 @@ import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReference;
@ -159,7 +161,8 @@ public class ResourceLeakDetector<T> {
}
/** the collection of active resources */
private final ConcurrentMap<DefaultResourceLeak<?>, LeakEntry> allLeaks = PlatformDependent.newConcurrentHashMap();
private final Set<DefaultResourceLeak<?>> allLeaks =
Collections.newSetFromMap(new ConcurrentHashMap<DefaultResourceLeak<?>, Boolean>());
private final ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
private final ConcurrentMap<String, Boolean> reportedLeaks = PlatformDependent.newConcurrentHashMap();
@ -353,13 +356,13 @@ public class ResourceLeakDetector<T> {
@SuppressWarnings("unused")
private volatile int droppedRecords;
private final ConcurrentMap<DefaultResourceLeak<?>, LeakEntry> allLeaks;
private final Set<DefaultResourceLeak<?>> allLeaks;
private final int trackedHash;
DefaultResourceLeak(
Object referent,
ReferenceQueue<Object> refQueue,
ConcurrentMap<DefaultResourceLeak<?>, LeakEntry> allLeaks) {
Set<DefaultResourceLeak<?>> allLeaks) {
super(referent, refQueue);
assert referent != null;
@ -368,7 +371,7 @@ public class ResourceLeakDetector<T> {
// It's important that we not store a reference to the referent as this would disallow it from
// be collected via the WeakReference.
trackedHash = System.identityHashCode(referent);
allLeaks.put(this, LeakEntry.INSTANCE);
allLeaks.add(this);
// Create a new Record so we always have the creation stacktrace included.
headUpdater.set(this, new Record(Record.BOTTOM));
this.allLeaks = allLeaks;
@ -441,13 +444,12 @@ public class ResourceLeakDetector<T> {
boolean dispose() {
clear();
return allLeaks.remove(this, LeakEntry.INSTANCE);
return allLeaks.remove(this);
}
@Override
public boolean close() {
// Use the ConcurrentMap remove method, which avoids allocating an iterator.
if (allLeaks.remove(this, LeakEntry.INSTANCE)) {
if (allLeaks.remove(this)) {
// Call clear so the reference is not even enqueued.
clear();
headUpdater.set(this, null);
@ -636,22 +638,4 @@ public class ResourceLeakDetector<T> {
return buf.toString();
}
}
private static final class LeakEntry {
static final LeakEntry INSTANCE = new LeakEntry();
private static final int HASH = System.identityHashCode(INSTANCE);
private LeakEntry() {
}
@Override
public int hashCode() {
return HASH;
}
@Override
public boolean equals(Object obj) {
return obj == this;
}
}
}