cache java caching guava canonicalization

java - cache - mi caché ideal usando guayaba



guava cache java (2)

No entiendo la imagen completa aquí, pero dos cosas.

  1. Dada esta declaración: "esta implementación desalojará los objetos incluso si son muy accesibles, una vez que se acabe su tiempo. Esto podría dar como resultado que múltiples objetos con el mismo UID floten en el entorno, lo cual no quiero". - suena como que solo necesitas usar weakKeys () y NO usar un desalojo por tiempo o por tamaño.

  2. O si desea incluir un "interno" en esto, usaría un Interners.newWeakInterner real.

MapMaker las últimas semanas, he estado intentando encontrar la implementación de mi caché ideal utilizando MapMaker de MapMaker . Vea mis dos preguntas anteriores here y here para seguir mi proceso de pensamiento.

Tomando lo que he aprendido, mi próximo intento es deshacerme de los valores blandos a favor de maximumSize y expireAfterAccess:

ConcurrentMap<String, MyObject> cache = new MapMaker() .maximumSize(MAXIMUM_SIZE) .expireAfterAccess(MINUTES_TO_EXPIRY, TimeUnit.MINUTES) .makeComputingMap(loadFunction);

dónde

Function<String, MyObject> loadFunction = new Function<String, MyObject>() { @Override public MyObject apply(String uidKey) { return getFromDataBase(uidKey); } };

Sin embargo, el único problema que me queda por resolver es que esta implementación desaloja los objetos incluso si son muy accesibles, una vez que se acabe el tiempo. Esto podría dar como resultado que varios objetos con el mismo UID floten en el entorno, lo cual no quiero (creo que lo que estoy tratando de lograr se conoce como canonicalización).

Así que, por lo que puedo decir, la única respuesta es tener un mapa adicional que funciona como un interno, que puedo verificar para ver si un objeto de datos todavía está en la memoria:

ConcurrentMap<String, MyObject> interner = new MapMaker() .weakValues() .makeMap();

y la función de carga sería revisada:

Function<String, MyObject> loadFunction = new Function<String, MyObject>() { @Override public MyObject apply(String uidKey) { MyObject dataObject = interner.get(uidKey); if (dataObject == null) { dataObject = getFromDataBase(uidKey); interner.put(uidKey, dataObject); } return dataObject; } };

Sin embargo, usar dos mapas en lugar de uno para el caché parece ineficiente. ¿Hay una forma más sofisticada de abordar esto? En general, ¿estoy haciendo esto de la manera correcta o debo reconsiderar mi estrategia de almacenamiento en caché?


Que dos mapas sean eficientes depende completamente de lo caro que sea getFromDatabase () y de cuán grandes sean sus objetos. No parece estar fuera de todos los límites razonables para hacer algo como esto.

En lo que respecta a la implementación, parece que probablemente puedas superponer tus mapas de una manera ligeramente diferente para obtener el comportamiento que deseas y aún tener buenas propiedades de concurrencia.

  1. Cree su primer mapa con valores débiles y coloque la función informática getFromDatabase () en este mapa.
  2. El segundo mapa es el que está expirando, también se está calculando, pero esta función solo se obtiene del primer mapa.

Haz todo tu acceso a través del segundo mapa.

En otras palabras, el mapa que caduca actúa para fijar un subconjunto de los objetos usados ​​más recientemente en la memoria, mientras que el mapa de referencia débil es el caché real.

-dg