12

He utilizado LinkedHashMap con accessOrder cierto junto con permitir un máximo de 500 entradas en cualquier momento como la memoria caché LRU para datos. Pero debido a problemas de escalabilidad, quiero pasar a una alternativa segura para subprocesos. ConcurrentHashMap parece bueno en ese sentido, pero carece de las características de accessOrder y removeEldestEntry(Map.Entry e) que se encuentran en LinkedHashMap. ¿Alguien puede señalar algún enlace o ayudarme a facilitar la implementación?¿Cómo implementar ConcurrentHashMap con características similares en LinkedHashMap?

+3

Este es un problema realmente difícil. Hemos intentado abordarlo en google-collections y aún no estamos del todo allí. Pero seremos ... –

+0

Pregunta similar: http://stackoverflow.com/questions/1391918/does-java-have-a-linkedconcurrenthashmap-data-structure – Vadzim

Respuesta

9

Hice algo similar recientemente con ConcurrentHashMap<String,CacheEntry>, donde CacheEntry ajusta el elemento actual y agrega estadísticas de desalojo de caché: tiempo de expiración, tiempo de inserción (para expulsión FIFO/LIFO), último tiempo utilizado (para desalojo LRU/MRU), número de visitas (para desalojo LFU/MFU), etc. El desalojo real se sincroniza y crea un ArrayList<CacheEntry> y realiza un Collections.sort() en él utilizando el Comparador apropiado para la estrategia de desalojo . Dado que esto es costoso, cada desalojo se corta en el 5% inferior de las entradas de caché. Sin embargo, estoy seguro de que la optimización del rendimiento ayudaría.

En su caso, ya que está haciendo FIFO, puede mantener un ConcurrentLinkedQueue por separado. Cuando agrega un objeto a ConcurrentHashMap, realice un ConcurrentLinkedQueue.add() de ese objeto. Cuando desee desalojar una entrada, haga una Simulación ConcurrentLinkedQueue.poll() para eliminar el objeto más antiguo, luego también elimínelo de ConcurrentHashMap.

Actualización: Otras posibilidades en esta área incluyen una Java Collections synchronization wrapper y Java 1.6 ConcurrentSkipListMap.

+0

Tu sugerencia parece mucho a la que necesito. Significa que tengo algunos gastos generales para mantener otros elementos que consumirán el mismo tamaño que el del conjunto del mapa. De todos modos, esto está bien para mí. – DKSRathore

+0

Sé que ha pasado un tiempo pero encontré su respuesta y ¿podría decirme cuándo recibió ArrayList de entradas expulsadas, entonces cómo las elimina de ConcurrentHashMap? ¿Usted itera sobre el Map.Entry comprobando si los valores son los mismos y luego quitándolo de Map usando su clave? ¿O extraño algo y lo haces de otra manera? – wawek

-2

Envuelva el mapa en Collections.synchronizedMap(). Si necesita llamar a métodos adicionales, entonces synchronize en el mapa que obtuvo de esta llamada, e invoque el método original en el mapa original (see the javadocs for an example). Lo mismo aplica cuando itera sobre las claves, etc.

+0

Aaron esto empeorará mis problemas de escalabilidad. Dado que la actualización del mapa se convertiría en serial. ConcurrentHashMap tiene una función para que más de uno pueda actualizar el mapa al mismo tiempo. – DKSRathore

+0

ConcHM tiene algunas propiedades específicas que no se asignan fácilmente a LinkedHM (es decir, permite insertarse simultáneamente siempre que el hash no se asocie a la misma clave de segmento). Esta optimización no es posible cuando necesita mantener el orden de inserción. Debe decidir cuál es más importante para usted. –

2

¿Ha intentado utilizar una de las muchas soluciones de almacenamiento en caché como ehcache? Puede intentar usar LinkedHashMap con un ReadWriteLock. Esto le daría acceso de lectura concurrente.

+0

Aún no. Pero EHcache sería mi otra alternativa. – DKSRathore

0

Menciona que desea resolver problemas de escalabilidad con una alternativa "segura para subprocesos". "Seguridad de subprocesos" aquí significa que la estructura es tolerante de intentos de acceso simultáneo, en el sentido de que no sufrirá daños por el uso simultáneo sin sincronización externa. Sin embargo, tal tolerancia no necesariamente ayuda a mejorar la "escalabilidad". En el enfoque más simple, aunque generalmente erróneo, intentará sincronizar su estructura internamente y aún así dejar las operaciones no atómicas check-then-act inseguras.

Las memorias caché LRU requieren al menos cierto conocimiento de la estructura total. Necesitan algo como el recuento de los miembros o el tamaño de los miembros para decidir cuándo expulsar, y luego deben poder coordinar el desalojo con intentos simultáneos de leer, agregar o eliminar elementos. Intentar reducir la sincronización necesaria para el acceso simultáneo a la estructura "principal" combate contra su mecanismo de desalojo, y obliga a que su política de desalojo sea menos precisa en sus garantías.

La respuesta actualmente aceptada menciona "cuando desea desalojar una entrada". Ahí radica el problema. ¿Cómo sabes cuándo quieres desalojar una entrada? ¿Qué otras operaciones necesita detener para tomar esta decisión?

1

Esto puede parecer viejo ahora, pero al menos solo para mi propio historial de seguimiento, voy a agregar mi solución aquí: Combiné ConcurrentHashMap que mapea K-> subclase de WeakReference, ConcurrentLinkedQueue, y una interfaz que define la deserialización de los objetos de valor basados ​​en K para ejecutar el almacenamiento en memoria caché LRU correctamente. La cola contiene refs fuertes, y el GC desalojará los valores de la memoria cuando sea apropiado. El seguimiento del tamaño de la cola involucró a AtomicInteger, ya que no se puede inspeccionar realmente la cola para determinar cuándo expulsar. El caché manejará el desalojo de/agregar a la cola, así como la administración del mapa. Si el GC desalojó el valor de la memoria, la implementación de la interfaz de deserialización manejará la recuperación del valor. También tuve otra implementación que involucraba spooling en disco/relectura de lo que estaba en la cola, pero eso fue mucho más lento que la solución que publiqué aquí, ya que tenía que sincronizar spooling/reading.

+0

Gracias, es bueno agregar su solución a una publicación, incluso cuando – Guillaume

Cuestiones relacionadas