Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

org.scoja.util
Class ExpiringLRUCache  view ExpiringLRUCache download ExpiringLRUCache.java

java.lang.Object
  extended byorg.scoja.util.ExpiringLRUCache

public class ExpiringLRUCache
extends java.lang.Object

Es una tabla con un tamaño limitado en espacio y en tiempo.

Está pensada para usarse en un contexto concurrente, en donde muchas hebras comparten los recursos de esta caché. Se supone que (1) los objetos de la caché tienen un coste de construcción y que, por tanto, hay que evitar que dos hebras construyan el mismo porque ambas lo vieron a la vez ausente. Además, también se supone que (2) los objetos deben liberar un recurso al final de su vida en la caché. La caché avisa de su muerte mediante ExpiringObject.expired() 55 . Curiosamente, estas dos suposiciones tienen una relación: cuando dos hebras construyen un mismo objeto, sólo uno de ellos termina en la caché, y el otro, si no se tiene buen cuidado, termina perdido, bloqueando su recurso hasta que se recoja de la basura.

La limitación en tiempo quiere decir que la caché mata todos los objetos que lleven más de un cierto tiempo sin haberse usado.

La limitiación en espacio tiene dos variantes. En la laxa, se admite que se sobrepase el máximo si son necesarios simultaneamente; esta interpretación no tiene problemas de interbloqueo. En la estricta, se deja detenidas a las peticiones que intenten sobrepasar el límite; esta interpretación tiene problemas de interbloqueo si las hebras piden varios recursos simultaneamente. Para nuestro uso en Scoja, ambas semánticas son adecuadas, porque cada hebra sólo pide un recurso: el fichero donde tiene que escribir. Por ahora sólo se implementa la laxa porque es más sencilla.

Forma de uso La forma de uso de esta caché es un tanto atípica. Para acceder a un elemento hay que utilizar el método get(Object) 55 ; pero aquí se acaban las similitudes con una tabla. Primero el resultado de este método no es el valor que estamos buscando, sino un LRUShell que nos permitirá llegar a ese valor. Segundo, hagamos lo que hagamos con el LRUShell, cuando hayamos terminado de usarlo debemos indicarlo llamando a su método LRUShell.release() 55 . Cuando se accede a un elemento con get(Object) 55 , su caché anota que se está usando e impide su destrucción, por mucho que se llene la caché, o por mucho tiempo que pase. Es cuando se llama a LRUShell.release() 55 cuando la caché entiende que ya no se está usando y lo empieza a tratar como un objeto que puede expirar. Por tanto, si olvidamos hacer esta llamada, terminaremos abarrotando la memoria con una caché llena de objetos que nunca van a morir.

El método get(Object) 55 devuelve un LRUShell incluso para las claves que nunca se han definido. Por supuesto este LRUShell no tiene ningún valor asociado y su método LRUShell.getValue() 55 devolverá null. Pero el comportamiento de LRUShell.getValue() 55 es bastante más complejo; si varias hebras acceden a la vez a un mismo LRUCache sin valor, solo la primera que ejecute getValue() verá un null; el resto de hebras se quedarán detenidas hasta que, o bien esa hebra da un valor con LRUShell.put(ExpiringObject) 55 , o indica que ya lo ha terminado de usar con LRUShell.release() 55 .

Cuando un objeto ya tiene valor, cualquier hebra puede acceder a su LRUShell y a su valor asociado, sin tener que esperar a otra. Es decir, esta caché no serializa el acceso a sus valores. Un valor puede expirar cuando ninguna hebra lo está usando, es decir, cuando todas la hebras que lo consiguieron con get() ya han ejecutado un release().

 LRUShell shell = null;
 try {
     shell = cache.get(key);
     if (shell.getValue() == null) {
         shell.put(new KillMe(value));
     }
 } finally {
     if (shell != null) shell.release();
 }
 


Nested Class Summary
private  class ExpiringLRUCache.Shell
           
 
Field Summary
protected  ExpiringLRUCache.Shell lruQueue
           
protected  java.util.Map map
           
protected  long maxInactivity
           
protected  int maxSize
           
 
Constructor Summary
ExpiringLRUCache(int maxSize, long maxInactivity)
           
 
Method Summary
 LRUShell get(java.lang.Object key)
           
protected  void kill(ExpiringLRUCache.Shell shell)
           
 void killAll()
           
protected  void killOldest(int free)
           
protected  void release(ExpiringLRUCache.Shell shell)
           
 void setInactivity(long maxInactivity)
           
 void setSize(int maxSize)
           
 java.lang.String toString()
          Convert this Object to a human-readable String.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

maxSize

protected int maxSize

maxInactivity

protected long maxInactivity

lruQueue

protected final ExpiringLRUCache.Shell lruQueue

map

protected final java.util.Map map
Constructor Detail

ExpiringLRUCache

public ExpiringLRUCache(int maxSize,
                        long maxInactivity)
Method Detail

setSize

public void setSize(int maxSize)

setInactivity

public void setInactivity(long maxInactivity)

get

public LRUShell get(java.lang.Object key)

release

protected void release(ExpiringLRUCache.Shell shell)

killOldest

protected void killOldest(int free)

kill

protected void kill(ExpiringLRUCache.Shell shell)

killAll

public void killAll()

toString

public java.lang.String toString()
Description copied from class: java.lang.Object
Convert this Object to a human-readable String. There are no limits placed on how long this String should be or what it should contain. We suggest you make it as intuitive as possible to be able to place it into System.out.println() 55 and such.

It is typical, but not required, to ensure that this method never completes abruptly with a java.lang.RuntimeException.

This method will be called when performing string concatenation with this object. If the result is null, string concatenation will instead use "null".

The default implementation returns getClass().getName() + "@" + Integer.toHexString(hashCode()).