
org.simpleframework.xml.util.WeakCache Maven / Gradle / Ivy
/*
* WeakCache.java July 2006
*
* Copyright (C) 2006, Niall Gallagher
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.simpleframework.xml.util;
import java.util.WeakHashMap;
import java.util.ArrayList;
import java.util.List;
/**
* The WeakCache
object is an implementation of a cache
* that holds on to cached items only if the key remains in memory.
* This is effectively like a concurrent hash map with weak keys, it
* ensures that multiple threads can concurrently access weak hash
* maps in a way that lowers contention for the locks used.
*
* @author Niall Gallagher
*/
public class WeakCache implements Cache {
/**
* This is used to store a list of segments for the cache.
*/
private SegmentList list;
/**
* Constructor for the WeakCache
object. This is
* used to create a cache that stores values in such a way that
* when the key is garbage collected the value is removed from
* the map. This is similar to the concurrent hash map.
*/
public WeakCache() {
this(10);
}
/**
* Constructor for the WeakCache
object. This is
* used to create a cache that stores values in such a way that
* when the key is garbage collected the value is removed from
* the map. This is similar to the concurrent hash map.
*
* @param size this is the number of segments within the cache
*/
public WeakCache(int size) {
this.list = new SegmentList(size);
}
/**
* This method is used to insert a key value mapping in to the
* cache. The value can later be retrieved or removed from the
* cache if desired. If the value associated with the key is
* null then nothing is stored within the cache.
*
* @param key this is the key to cache the provided value to
* @param value this is the value that is to be cached
*/
public void cache(K key, V value) {
map(key).cache(key, value);
}
/**
* This is used to exclusively take the value mapped to the
* specified key from the cache. Invoking this is effectively
* removing the value from the cache.
*
* @param key this is the key to acquire the cache value with
*
* @return this returns the value mapped to the specified key
*/
public V take(K key) {
return map(key).take(key);
}
/**
* This method is used to get the value from the cache that is
* mapped to the specified key. If there is no value mapped to
* the specified key then this method will return a null.
*
* @param key this is the key to acquire the cache value with
*
* @return this returns the value mapped to the specified key
*/
public V fetch(K key) {
return map(key).fetch(key);
}
/**
* This is used to determine whether the specified key exists
* with in the cache. Typically this can be done using the
* fetch method, which will acquire the object.
*
* @param key this is the key to check within this segment
*
* @return true if the specified key is within the cache
*/
public boolean contains(K key) {
return map(key).contains(key);
}
/**
* This method is used to acquire a Segment
using
* the keys has code. This method effectively uses the hash to
* find a specific segment within the fixed list of segments.
*
* @param key this is the key used to acquire the segment
*
* @return this returns the segment used to get acquire value
*/
private Segment map(K key) {
return list.get(key);
}
/**
* This is used to maintain a list of segments. All segments that
* are stored by this object can be acquired using a given key.
* The keys hash is used to select the segment, this ensures that
* all read and write operations with the same key result in the
* same segment object within this list.
*
* @author Niall Gallagher
*/
private class SegmentList {
/**
* The list of segment objects maintained by this object.
*/
private List list;
/**
* Represents the number of segments this object maintains.
*/
private int size;
/**
* Constructor for the SegmentList
object. This
* is used to create a list of weak hash maps that can be
* acquired using the hash code of a given key.
*
* @param size this is the number of hash maps to maintain
*/
public SegmentList(int size) {
this.list = new ArrayList();
this.size = size;
this.create(size);
}
/**
* This is used to acquire the segment using the given key.
* The keys hash is used to determine the index within the
* list to acquire the segment, which is a synchronized weak
* hash map storing the key value pairs for a given hash.
*
* @param key this is the key used to determine the segment
*
* @return the segment that is stored at the resolved hash
*/
public Segment get(K key) {
int segment = segment(key);
if(segment < size) {
return list.get(segment);
}
return null;
}
/**
* Upon initialization the segment list is populated in such
* a way that synchronization is not needed. Each segment is
* created and stored in an increasing index within the list.
*
* @param size this is the number of segments to be used
*/
private void create(int size) {
int count = size;
while(count-- > 0) {
list.add(new Segment());
}
}
/**
* This method performs the translation of the key hash code
* to the segment index within the list. Translation is done
* by acquiring the modulus of the hash and the list size.
*
* @param key this is the key used to resolve the index
*
* @return the index of the segment within the list
*/
private int segment(K key) {
return Math.abs(key.hashCode() % size);
}
}
/**
* The segment is effectively a synchronized weak hash map. If is
* used to store the key value pairs in such a way that they are
* kept only as long as the garbage collector does not collect
* the key. This ensures the cache does not cause memory issues.
*
* @author Niall Gallagher
*/
private class Segment extends WeakHashMap {
/**
* This method is used to insert a key value mapping in to the
* cache. The value can later be retrieved or removed from the
* cache if desired. If the value associated with the key is
* null then nothing is stored within the cache.
*
* @param key this is the key to cache the provided value to
* @param value this is the value that is to be cached
*/
public synchronized void cache(K key, V value) {
put(key, value);
}
/**
* This method is used to get the value from the cache that is
* mapped to the specified key. If there is no value mapped to
* the specified key then this method will return a null.
*
* @param key this is the key to acquire the cache value with
*
* @return this returns the value mapped to the specified key
*/
public synchronized V fetch(K key) {
return get(key);
}
/**
* This is used to exclusively take the value mapped to the
* specified key from the cache. Invoking this is effectively
* removing the value from the cache.
*
* @param key this is the key to acquire the cache value with
*
* @return this returns the value mapped to the specified key
*/
public synchronized V take(K key) {
return remove(key);
}
/**
* This is used to determine whether the specified key exists
* with in the cache. Typically this can be done using the
* fetch method, which will acquire the object.
*
* @param key this is the key to check within this segment
*
* @return true if the specified key is within the cache
*/
public synchronized boolean contains(K key) {
return containsKey(key);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy