blob: 60140c420f6156ad69ea0362699647a395102ba9 [file] [log] [blame]
/*
* Copyright (c) 2007-2009, 2011-2013, 2015 Eike Stepper (Berlin, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.net4j.util.ref;
import java.lang.ref.ReferenceQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* A {@link ConcurrentMap} implementation that uses {@link KeyedReference} instances ({@link KeyedStrongReference},
* {@link KeyedSoftReference}, {@link KeyedWeakReference} or {@link KeyedPhantomReference}) as its values.
* <p>
* A <code>ReferenceValueMap</code> can be used to cache mappings until the <em>value</em> of the mapping is no longer
* reachable from outside of the map
* <p>
* <b>Note:</b> This map is not synchronized. If it is to be used by multiple threads concurrently the user is
* responsible for applying proper external synchronization!
*
* @author Eike Stepper
*/
public abstract class ReferenceValueMap<K, V> extends ReferenceValueMap2<K, V>implements ConcurrentMap<K, V>
{
public ReferenceValueMap()
{
this(new ConcurrentHashMap<K, KeyedReference<K, V>>());
}
public ReferenceValueMap(ConcurrentMap<K, KeyedReference<K, V>> map)
{
super(map);
}
public V putIfAbsent(K key, V value)
{
try
{
KeyedReference<K, V> ref = createReference(key, value, queue);
KeyedReference<K, V> oldRef = ((ConcurrentMap<K, KeyedReference<K, V>>)map).putIfAbsent(key, ref);
return dereference(oldRef);
}
finally
{
purgeQueue();
}
}
public V replace(K key, V value)
{
try
{
KeyedReference<K, V> ref = createReference(key, value, queue);
KeyedReference<K, V> oldRef = ((ConcurrentMap<K, KeyedReference<K, V>>)map).replace(key, ref);
return dereference(oldRef);
}
finally
{
purgeQueue();
}
}
public boolean replace(K key, V oldValue, V newValue)
{
try
{
// TODO Consider a dummy KeyedReference class for oldRef
KeyedReference<K, V> oldRef = createReference(key, oldValue, queue);
KeyedReference<K, V> newRef = createReference(key, newValue, queue);
return ((ConcurrentMap<K, KeyedReference<K, V>>)map).replace(key, oldRef, newRef);
}
finally
{
purgeQueue();
}
}
public boolean remove(Object key, Object value)
{
// TODO Consider a dummy KeyedReference class for value
return ((ConcurrentMap<K, KeyedReference<K, V>>)map).remove(key, value);
}
/**
* @author Eike Stepper
*/
public static class Strong<K, V> extends ReferenceValueMap<K, V>
{
public Strong()
{
}
public Strong(ConcurrentMap<K, KeyedReference<K, V>> map)
{
super(map);
}
@Override
protected KeyedReference<K, V> createReference(K key, V value, ReferenceQueue<V> queue)
{
return new KeyedStrongReference<K, V>(key, value);
}
@Override
protected ReferenceQueue<V> createQueue()
{
return null;
}
}
/**
* @author Eike Stepper
*/
public static class Soft<K, V> extends ReferenceValueMap<K, V>
{
public Soft()
{
}
public Soft(ConcurrentMap<K, KeyedReference<K, V>> map)
{
super(map);
}
@Override
protected KeyedReference<K, V> createReference(K key, V value, ReferenceQueue<V> queue)
{
return new KeyedSoftReference<K, V>(key, value, queue);
}
}
/**
* @author Eike Stepper
*/
public static class Weak<K, V> extends ReferenceValueMap<K, V>
{
public Weak()
{
}
public Weak(ConcurrentMap<K, KeyedReference<K, V>> map)
{
super(map);
}
@Override
protected KeyedReference<K, V> createReference(K key, V value, ReferenceQueue<V> queue)
{
return new KeyedWeakReference<K, V>(key, value, queue);
}
}
}