/** * Returns a new {@link MapCache MapCache} instance backed by a {@link SoftHashMap}. * * @param name the name of the cache * @return a new {@link MapCache MapCache} instance backed by a {@link SoftHashMap}. */ @Override protected Cache createCache(String name) { return new MapCache<Object, Object>(name, new SoftHashMap<Object, Object>()); } }
/** * Creates a new entry, but wraps the value in a SoftValue instance to enable auto garbage collection. */ public V put(K key, V value) { processQueue(); // throw out garbage collected values first SoftValue<V, K> sv = new SoftValue<V, K>(value, key, queue); SoftValue<V, K> previous = map.put(key, sv); addToStrongReferences(value); return previous != null ? previous.get() : null; }
public Collection<V> values() { processQueue(); Collection<K> keys = map.keySet(); if (keys.isEmpty()) { //noinspection unchecked return Collections.EMPTY_SET; } Collection<V> values = new ArrayList<V>(keys.size()); for (K key : keys) { V v = get(key); if (v != null) { values.add(v); } } return values; }
public boolean containsValue(Object value) { processQueue(); Collection values = values(); return values != null && values.contains(value); }
public void putAll(Map<? extends K, ? extends V> m) { if (m == null || m.isEmpty()) { processQueue(); return; } for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) { put(entry.getKey(), entry.getValue()); } }
public boolean containsKey(Object key) { processQueue(); return map.containsKey(key); }
/** * Creates a {@code SoftHashMap} backed by the specified {@code source}, with a default retention * size of {@link #DEFAULT_RETENTION_SIZE DEFAULT_RETENTION_SIZE} (100 entries). * * @param source the backing map to populate this {@code SoftHashMap} * @see #SoftHashMap(Map,int) */ public SoftHashMap(Map<K, V> source) { this(DEFAULT_RETENTION_SIZE); putAll(source); }
private void addToStrongReferences(V result) { strongReferencesLock.lock(); try { strongReferences.add(result); trimStrongReferencesIfNecessary(); } finally { strongReferencesLock.unlock(); } }
public Set<K> keySet() { processQueue(); return map.keySet(); }
public void putAll(Map<? extends K, ? extends V> m) { if (m == null || m.isEmpty()) { processQueue(); return; } for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) { put(entry.getKey(), entry.getValue()); } }
public boolean containsValue(Object value) { processQueue(); Collection values = values(); return values != null && values.contains(value); }
/** * Creates a {@code SoftHashMap} backed by the specified {@code source}, with the specified retention size. * <p/> * The retention size (n) is the total number of most recent entries in the map that will be strongly referenced * (ie 'retained') to prevent them from being eagerly garbage collected. That is, the point of a SoftHashMap is to * allow the garbage collector to remove as many entries from this map as it desires, but there will always be (n) * elements retained after a GC due to the strong references. * <p/> * Note that in a highly concurrent environments the exact total number of strong references may differ slightly * than the actual <code>retentionSize</code> value. This number is intended to be a best-effort retention low * water mark. * * @param source the backing map to populate this {@code SoftHashMap} * @param retentionSize the total number of most recent entries in the map that will be strongly referenced * (retained), preventing them from being eagerly garbage collected by the JVM. */ public SoftHashMap(Map<K, V> source, int retentionSize) { this(retentionSize); putAll(source); }
private void addToStrongReferences(V result) { strongReferencesLock.lock(); try { strongReferences.add(result); trimStrongReferencesIfNecessary(); } finally { strongReferencesLock.unlock(); } }
public V get(Object key) { processQueue(); V result = null; SoftValue<V, K> value = map.get(key); if (value != null) { //unwrap the 'real' value from the SoftReference result = value.get(); if (result == null) { //The wrapped value was garbage collected, so remove this entry from the backing map: //noinspection SuspiciousMethodCalls map.remove(key); } else { //Add this value to the beginning of the strong reference queue (FIFO). addToStrongReferences(result); } } return result; }
public Set<Map.Entry<K, V>> entrySet() { processQueue(); // throw out garbage collected values first Collection<K> keys = map.keySet(); if (keys.isEmpty()) { //noinspection unchecked return Collections.EMPTY_SET; } Map<K, V> kvPairs = new HashMap<K, V>(keys.size()); for (K key : keys) { V v = get(key); if (v != null) { kvPairs.put(key, v); } } return kvPairs.entrySet(); }
public int size() { processQueue(); // throw out garbage collected values first return map.size(); }
public void putAll(Map<? extends K, ? extends V> m) { if (m == null || m.isEmpty()) { processQueue(); return; } for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) { put(entry.getKey(), entry.getValue()); } }
public boolean containsValue(Object value) { processQueue(); Collection values = values(); return values != null && values.contains(value); }
/** * Creates a {@code SoftHashMap} backed by the specified {@code source}, with a default retention * size of {@link #DEFAULT_RETENTION_SIZE DEFAULT_RETENTION_SIZE} (100 entries). * * @param source the backing map to populate this {@code SoftHashMap} * @see #SoftHashMap(Map,int) */ public SoftHashMap(Map<K, V> source) { this(DEFAULT_RETENTION_SIZE); putAll(source); }
private void addToStrongReferences(V result) { strongReferencesLock.lock(); try { strongReferences.add(result); trimStrongReferencesIfNecessary(); } finally { strongReferencesLock.unlock(); } }