us.bpsm.edn.Interner Maven / Gradle / Ivy
// (c) 2012 B Smith-Mannschott -- Distributed under the Eclipse Public License
package us.bpsm.edn;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
class Interner {
private final ConcurrentHashMap> table =
new ConcurrentHashMap>();
private final ReferenceQueue refQueue = new ReferenceQueue();
public V intern(K key, V value) {
while (true) {
clearDeadEntries();
WeakReference newRef = new WeakReference(value, refQueue);
Reference existingRef = table.putIfAbsent(key, newRef);
if (existingRef == null) {
// newRef has been entered into the cache
return value;
}
// existingRef was found in the cache; newRef is garbage
V existingValue = existingRef.get();
if (existingValue != null) {
return existingValue;
}
// existingRef's referent has been collected out from under us
table.remove(key, existingRef);
}
}
private void clearDeadEntries() {
if (refQueue.poll() == null) {
// empty queue indicates that there's nothing to clear
return;
}
while (refQueue.poll() != null) {
// wait until there's nothing more in flight in the queue
}
for (Map.Entry> me: table.entrySet()) {
Reference ref = me.getValue();
if (ref != null && ref.get() == null) {
table.remove(me.getKey(), ref);
}
}
}
}