com.ejie.r01f.collections
Class SoftHashMap
java.lang.Object
java.util.AbstractMap
com.ejie.r01f.collections.SoftHashMap
All Implemented Interfaces: java.util.Map
public class SoftHashMap extends java.util.AbstractMapimplements java.util.Map
Mapa respaldado por objetos SoftReference que se liberan cuando:
1.- El objeto del cache NO tiene StrongReferences apuntándole
2.- El GC necesita memoria
IMPORTANTE: Diferencia entre objetos StrongReference, WeakReference y SoftReference
- Una StrongReference es una referencia java "normal":
StringBuffer sb = new StringBuffer("");
sb es una StrongReference al StringBuffer recien creado
Si un objeto es "alcanzable" por una cadena de StrongReferences, entonces NO es procesado por el GC
OJO!! Cuando un objeto se indexa en un mapa se establece una StrongReference al mismo
map.put(key,obj) :< obj tiene una StrongReference y NO es limpiado por el GC
- Una WeakReference es una referencia a un objeto que permite al GC liberar el objeto al que referencia la WeakReference
WeakReference wr = new WeakReference(obj)
en este caso obj tiene una WeakReference sobre él, lo que permite al GC liberar obj (al llamar a wr.get() se devuelve null)
Un WeakHashMap es un mapa "normal" en el que las CLAVES (no los valores!) son WeakReferences. Cuando las CLAVES dejan de ser utilizadas
(no hay ninguna StringReference sobre ellas), pueden ser liberadas por el GC
- Una SoftReference es como una WeakReference salvo que es menos "propensa" a que el objeto que referencia sea liberado por el GC
* En el caso de una WeakReference sobre un objeto, el GC libera el objeto en cuanto no tiene ninguna StrongReference sobre el mismo
* En el caso de una SoftReference sobre un objeto, el GC libera el objeto en cuanto necesita memoria
Por lo tanto, las SoftReferences son adecuadas para la construcción de caches... en especial mucho más que las WeakReferences puesto que un
WeakHashMap contiene WeakReferences a las CLAVES y normalmente NO se guardan StrongReferences sobre las claves, por lo que enseguida (en el siguiente ciclo GC)
se libera el objeto de la cache. Un SoftHashMap es mucho más adecuado pues la entrada permanece hasta que es necesaria la memoria.
El problema es que la JVM NO proporciona una implementación de un SoftHasMap.
Esta clase es una implementación de la misma en base a la implementacion de WeakHashMap cambiando WeakReference por SoftReference
Así como en el WeakHashMap se guardan WeakReferences a las CLAVES, en esta clase se guardan SoftReferences tambien a las CLAVES
de forma que una clave (y por tanto el objeto referenciado) se liberan en cuanto se necesita memoria, a diferencia de un WeakHashMap
que se libera en cuanto la clave no tiene StrongReferences... es decir, habitualmente muy pronto.
En el mapa se pueden introducir valores nulos para la clave o el valor de una entrada
Al igual que casi todas las clases Collections, esta clase NO está sincronizada.
Para obtener una versión thread safe se debe utilizar Collections.synchronizedMap
El comportamiento de la clase viene determinado por el GC: dado que las entradas
del mapa son eliminadas "transparentemente" por el GC, la clase se comporta como si
un thread silenciosamente liberara entradas:
En particular, aunque se haga un synchronize sobre una instancia de SoftHashMap
y se llame a uno de los método mutadores, es posible obtener resultados "extraños":
- size
puede devolver valores distintos
- isEmpty
puede devolver primero false y luego true
- containsKey
para una clave puede devolver primero true y luego false
- get
para una clave puede devolver un valor y luego null
- put
puede devolver null y luego un valor
- remove
puede devolver false para una clave que anteriormente estaba en el mapa
- En dos examenes sucesiveos keySet, valueSet y entrySet pueden devolver valores distintos (menos elementos)
La implementación está basada en un Wrapper de un HashMap.
Dado que no se tiene acceso a la implementación interna del HashMap, los valores que se almacenan deben
tener la "logica" para saber si han de ser eliminados del HashMap ya que han sido descartados por el GC
El HashMap por lo tanto mapea las claves con instancias de la clase ValueCell que simplemente es
una extensión de la clase SoftReference.
Constructor Summary
SoftHashMap ()
Constructor por defecto
SoftHashMap (int initialCapacity)
Constructor en base a una capacidad inicial
SoftHashMap (int initialCapacity,
float loadFactor)
Constructor en base a una capacidad y factor de carga
Method Summary
void
clear ()
Eliminar todas las entradas de la cache
boolean
containsKey (java.lang.Object key)
Devuelve true si la cache contiene un elemento para la clave suministrada
Si NO existe valor para la clave NO se llama al método fill
OJO!
java.util.Set
entrySet ()
Devuelve un Set
con las entradas de la cache.
java.lang.Object
get (java.lang.Object key)
Devuelve el valor almacenado en la cache para la clave especificada.
boolean
isEmpty ()
Devuelve true si la cache NO contiene elementos
OJO!
java.lang.Object
put (java.lang.Object key,
java.lang.Object value)
Añadir un objeo a la tabla asociado a la clave dada
Si la tabla ya contenía un objeto para la clave, se devuelve este objeto
java.lang.Object
remove (java.lang.Object key)
Eliminar el objeto cacheado en la clave dada (si existe en la tabla)
int
size ()
Devuelve el numero de registros en la cache.
Methods inherited from class java.util.AbstractMap
containsValue, equals, hashCode, keySet, putAll, toString, values
Methods inherited from class java.lang.Object
getClass, notify, notifyAll, wait, wait, wait
Methods inherited from interface java.util.Map
containsValue, equals, hashCode, keySet, putAll, values
SoftHashMap
public SoftHashMap ()
Constructor por defecto
SoftHashMap
public SoftHashMap (int initialCapacity,
float loadFactor)
Constructor en base a una capacidad y factor de carga
Parameters: initialCapacity
- capacidad inicial de la cacheloadFactor
- numero entre 0.0 y 1.0 que indica el factor de carga del
mapa subyacente
Throws:
java.lang.IllegalArgumentException
- Si la capacidad inicial es menor o igual que cero o el
factor de carga es menor que cero o mayor que 1
SoftHashMap
public SoftHashMap (int initialCapacity)
Constructor en base a una capacidad inicial
Parameters: initialCapacity
- capacidad inicial de la cache
Throws:
java.lang.IllegalArgumentException
- Si la capacidad inicial es menor o igual que cero o el
factor de carga es menor que cero o mayor que 1
size
public int size ()
Devuelve el numero de registros en la cache.
OJO! Dado que el GC puede estar liberando elementos de la cache, puede que un momento dado
devuelva un valor mayor que en una siguiente consulta
Specified by: size
in interface java.util.Map
isEmpty
public boolean isEmpty ()
Devuelve true si la cache NO contiene elementos
OJO! Dado que el GC puede estar liberando elementos de la cache, puede que en un momento dado
devuelva false y en la siguiente consulta true
Specified by: isEmpty
in interface java.util.Map
containsKey
public boolean containsKey (java.lang.Object key)
Devuelve true si la cache contiene un elemento para la clave suministrada
Si NO existe valor para la clave NO se llama al método fill
OJO! Dado que el GC puede estar liberando elementos de la cache, puede que en un momento dado
devuelva true y en la siguiente consulta false
Specified by: containsKey
in interface java.util.Map
Parameters: key
- la clave que se desea saber si existe en la cache
get
public java.lang.Object get (java.lang.Object key)
Devuelve el valor almacenado en la cache para la clave especificada.
Si en la cache NO existe un objeto para esta clave, se invoca al metodo fill
para
obtener el objeto a cachear.
IMPORTANTE!
Este método actualiza la cache y por lo tanto es un metodo mutator que puede dar lugar a la excepcion
ConcurrentModificationException
si es invocado mientras se está iterando.
Specified by: get
in interface java.util.Map
Parameters: key
- la clave del valor que se quiere recuperarSee Also: #fill
put
public java.lang.Object put (java.lang.Object key,
java.lang.Object value)
Añadir un objeo a la tabla asociado a la clave dada
Si la tabla ya contenía un objeto para la clave, se devuelve este objeto
Specified by: put
in interface java.util.Map
Parameters: key
- la clave a la que se asocia el objetovalue
- el objeto que se guarda en la tabla
Returns: el objeto que estaba previamente almacenado en la tabla en la clave
null si antes NO habia nada en la tabla para la clave
remove
public java.lang.Object remove (java.lang.Object key)
Eliminar el objeto cacheado en la clave dada (si existe en la tabla)
Specified by: remove
in interface java.util.Map
Parameters: key
- la clave del objeto a eliminar
Returns: el objeto que estaba almacenado en la tabla en la clave o null si no había nada
clear
public void clear ()
Eliminar todas las entradas de la cache
Specified by: clear
in interface java.util.Map
entrySet
public java.util.Set entrySet ()
Devuelve un Set
con las entradas de la cache.
Specified by: entrySet
in interface java.util.Map