com.ejie.r01f.collections
Class SoftCache

java.lang.Object
  extended byjava.util.AbstractMap
      extended bycom.ejie.r01f.collections.SoftCache
All Implemented Interfaces:
java.util.Map

public abstract class SoftCache
extends java.util.AbstractMap
implements java.util.Map

Caché respaldado por un mapa cuya memoria se libera 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 cache 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 uso típio de esta clase es extenderla y sobre-escribir el metodo fill Cuando se invoca al método get para una clave que NO está en la cache, se llamará al método fill que intentará obtener este valor y lo cacheara Por ejemplo, una cache de objetos MyObj sería algo como:
     public class MyObjCache extends SoftCache {
         protected Object fill(Object key) {
         		// ... codigo para obtener myObj correspondiente a key ...
             	return myObj;
         }
     }
 
El comportamiento de la clase viene determinado por el GC: dado que las entradas del cache 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 SoftCache 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
SoftCache()
          Constructor por defecto
SoftCache(int initialCapacity)
          Constructor en base a una capacidad inicial
SoftCache(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
 

Constructor Detail

SoftCache

public SoftCache()
Constructor por defecto


SoftCache

public SoftCache(int initialCapacity,
                 float loadFactor)
Constructor en base a una capacidad y factor de carga

Parameters:
initialCapacity - capacidad inicial de la cache
loadFactor - 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

SoftCache

public SoftCache(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
Method Detail

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 recuperar
See 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 objeto
value - 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