HashMap con valores débiles

Estoy implementando un caché para objetos almacenados de forma persistente. La idea es:

  • Método getObjectFromPersistence(long id); ///Takes about 3 seconds getObjectFromPersistence(long id); ///Takes about 3 seconds
  • Método getObjectFromCache(long id) //Instantly

Y tiene un método: getObject(long id) con el siguiente pseudocódigo:

 synchronized(this){ CustomObject result= getObjectFromCache(id) if (result==null){ result=getObjectFromPersistence(id); addToCache(result); } return result; } 

Pero tengo que permitir que el objeto CustomObject sea recopilado por el recolector de basura. Hasta ahora estaba usando un HashMap<Long,WeakReference<CustomObject> para la implementación. El problema es que durante el tiempo que el HashMap se llena de WeakReferences vacío.

He comprobado WeakHashMap pero allí las llaves son débiles (y los valores son todavía referencias fuertes) así que tener los largos con WeakReferences no tiene sentido.

¿Cuál es la mejor solución para resolver este problema? ¿Hay algún "WeakHashMap inverso" o algo similar?

Gracias

Usted puede utilizar el Guava MapMaker para esto:

 ConcurrentMap<Long, CustomObject> graphs = new MapMaker() .weakValues() .makeMap(); 

Incluso puede incluir la parte de cálculo sustituyendo makeMap() por esto:

  .makeComputingMap( new Function<Long, CustomObject>() { public CustomObject apply(Long id) { return getObjectFromPersistence(id); } }); 

Puesto que lo que estás escribiendo se parece mucho a una memoria caché, el caché más nuevo y más especializado (construido a través de CacheBuilder ) puede ser aún más relevante para ti. No implementa la interfaz de Map directamente, pero proporciona incluso más controles que puede que desee para una caché.

¿Has probado android.util.LruCache (es una clase SDK11 pero también está en el paquete de compatibilidad como android.support.v4.util.LruCache ). No implementa java.util.Map pero funciona como un mapa y se puede definir la cantidad de memoria que se necesitará y se descargará antiguos (objetos en caché no utilizados por sí mismo).

Una WeakReference se añade a su ReferenceQueue suministrado en el momento de la construcción cuando se recoge su referencia.

Puede poll la ReferenceQueue cada vez que acceda a la caché y mantener una HashMap<WeakReference<CustomObject>,Long> para saber qué entrada quitar si se encuentra una referencia en la cola.

De forma alternativa, si la caché no se utiliza con frecuencia, puede ver la cola en un subproceso separado.

Usted podría comenzar una "limpieza" – Hilo de vez en cuando. Tal vez si el tamaño de su mapa supera un umbral, pero como máximo cada 5 minutos … algo así.

Mantenga los ciclos de limpieza cortos para no bloquear la funcionalidad principal.

Creo que la mejor opción (si una dependencia de Guava es indeseable) sería usar una subclase personalizada de WeakReference que recuerde su ID, de modo que su hilo de limpieza puede eliminar los valores débiles durante la limpieza de los WeakReferences.

La implementación de la referencia débil, con el necesario ReferenceQueue y el hilo de limpieza sería algo como esto:

 class CustomObjectAccess { private static final ReferenceQueue<CustomObject> releasedCustomObjects = new ReferenceQueue<>(); static { Thread cleanupThread = new Thread("CustomObject cleanup thread") while (true) { CustomObjectWeakReference freed = (CustomObjectWeakReference) CustomObjectWeakReference.releasedCustomObjects.remove(); cache.remove(freed.id); } }; cleanupThread.start(); } private Map<CustomObjectID, CustomObjectWeakReference> cache; public CustomObject get(CustomObjectID id) { synchronized(this){ CustomObject result= getFromCache(id); if (result==null) { result=getObjectFromPersistence(id); addToCache(result); } } return result; } private addToCache(CustomObject co) { cache.put(CustomObject.getID(), new CustomObjectWeakReference(co)); } private getFromCache(CustomObjectID id) { WeakReference<CustomObject> weak = cache.get(id); if (weak != null) { return weak.get(); } return null; } class CustomObjectWeakReference extends WeakReference<CustomObject> { private final CustomObjectID id; CustomObjectWeakReference(CustomObject co) { super(co, releasedCustomObjects); this.id = co.getID(); } } } 
  • Cortar contenido en TextView
  • Parallax XY y cálculo de la rotación
  • Problemas con el tutorial de Parse (Android)
  • La generación de Gradle no pudo resolver la dependencia de la biblioteca aar (trnql sdk)
  • Obtener el título de la página web de setWebViewClient?
  • ¿Cómo configurar el icono de cada ficha en un fragmentopageradapter a una animación gif?
  • Android Java runOnUiThread ()
  • cómo puedo agregar elementos a listview dinámicamente en android
  • Implementación de HeartBeat en Atmosphere Framework (Android)
  • Cómo conseguir que Powermock funcione con Dexmaker
  • Vista de reciclador - cambia el tamaño de la vista de elemento mientras se desplaza (para efecto de carrusel)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.