structures sheet data cheat and algorithms java data-structures

and - java data structures cheat sheet



¿Java tiene una estructura de datos "LinkedConcurrentHashMap"? (8)

Necesito una estructura de datos que sea LinkedHashMap y que sea segura para subprocesos.

Cómo puedo hacer eso ?


Acabo de probar el LRU vinculado sincronizado Mapa basado en el orden de inserción LinkedConcurrentHashMap ; con bloqueo de lectura / escritura para la sincronización. Entonces cuando estás usando iterador; debe adquirir WriteLock para evitar ConcurrentModificationException.
Esto es mejor que Collections.synchronizedMap.

public class LinkedConcurrentHashMap<K, V> { private LinkedHashMap<K, V> linkedHashMap = null; private final int cacheSize; private ReadWriteLock readWriteLock = null; public LinkedConcurrentHashMap(LinkedHashMap<K, V> psCacheMap, int size) { this.linkedHashMap = psCacheMap; cacheSize = size; readWriteLock=new ReentrantReadWriteLock(); } public void put(K key, V value) throws SQLException{ Lock writeLock=readWriteLock.writeLock(); try{ writeLock.lock(); if(linkedHashMap.size() >= cacheSize && cacheSize > 0){ K oldAgedKey = linkedHashMap.keySet().iterator().next(); remove(oldAgedKey); } linkedHashMap.put(key, value); }finally{ writeLock.unlock(); } } public V get(K key){ Lock readLock=readWriteLock.readLock(); try{ readLock.lock(); return linkedHashMap.get(key); }finally{ readLock.unlock(); } } public boolean containsKey(K key){ Lock readLock=readWriteLock.readLock(); try{ readLock.lock(); return linkedHashMap.containsKey(key); }finally{ readLock.unlock(); } } public V remove(K key){ Lock writeLock=readWriteLock.writeLock(); try{ writeLock.lock(); return linkedHashMap.remove(key); }finally{ writeLock.unlock(); } } public ReadWriteLock getLock(){ return readWriteLock; } public Set<Map.Entry<K, V>> entrySet(){ return linkedHashMap.entrySet(); } }


Dado que el ConcurrentHashMap ofrece algunos métodos adicionales importantes que no están en la interfaz del Mapa, simplemente envolviendo un LinkedHashMap con un synchronizedMap no le dará la misma funcionalidad, en particular, no le darán nada como el putIfAbsent (), reemplace (key, oldValue, newValue) y remove (key, oldValue) métodos que hacen que ConcurrentHashMap sea tan útil.

A menos que haya alguna biblioteca de Apache que haya implementado lo que desea, probablemente tendrá que usar un LinkedHashMap y proporcionar sus propios {} bloques sincronizados adecuados.


Hay una implementación disponible bajo el código de Google. Una cita de su sitio:

Una versión de alto rendimiento de java.util.LinkedHashMap para usar como un caché de software.

Diseño

  • Una lista vinculada simultánea se ejecuta a través de ConcurrentHashMap para proporcionar el pedido de desalojo.
  • Admite la inserción y el acceso a políticas de desalojo ordenadas (FIFO, LRU y Second Chance).

Hay varios enfoques diferentes para este problema. Podrías usar:

Collections.synchronizedMap(new LinkedHashMap());

como han sugerido las otras respuestas, pero esto tiene varios inconvenientes que deberá tener en cuenta. Lo más notable es que a menudo necesitará mantener el bloqueo sincronizado de las colecciones al iterar sobre la colección, lo que a su vez impide que otros subprocesos accedan a la colección hasta que haya completado la iteración. ( Ver teoría y práctica de Java: clases de colecciones concurrentes ). Por ejemplo:

synchronized(map) { for (Object obj: map) { // Do work here } }

Utilizando

new ConcurrentHashMap();

es probablemente una mejor opción ya que no será necesario bloquear la colección para iterar sobre ella.

Finalmente, es posible que desee considerar un enfoque de programación más funcional . Es decir, podrías considerar el mapa como esencialmente inmutable. En lugar de agregar a un mapa existente, creará uno nuevo que contenga el contenido del mapa anterior más la nueva adición. Esto suena bastante extraño al principio, pero en realidad es la forma en que Scala trata con la concurrencia y las colecciones


La respuesta es prácticamente no, no hay nada equivalente a un ConcurrentHashMap que esté ordenado (como LinkedHashMap). Como señalaron otras personas, puede envolver su colección usando Collections.synchronizedMap (-yourmap-) sin embargo, esto no le dará el mismo nivel de bloqueo de grano fino. Simplemente bloqueará todo el mapa en cada operación.

Su mejor opción es usar sincronizado en cualquier acceso al mapa (donde sea importante, por supuesto. Puede que no le interesen las lecturas sucias, por ejemplo) o escribir un contenedor alrededor del mapa que determine cuándo debería o no bloquearse. .


Puede envolver el mapa en Collections.synchronizedMap para obtener un hashmap sincronizado que mantenga el orden de inserción. Esto no es tan eficiente como un ConcurrentHashMap (y no implementa los métodos de interfaz extra de ConcurrentMap), pero sí le ofrece el comportamiento (algo) seguro de subprocesos.

Incluso las poderosas Google Collections no parecen haber resuelto este problema en particular todavía. Sin embargo, hay un proyecto que intenta abordar el problema.

Digo algo sobre la sincronización, porque la iteración aún no es segura para subprocesos en el sentido de que pueden ocurrir excepciones de modificación simultáneas.


Puede usar un ConcurrentSkipListMap, solo disponible en Java SE / EE 6 o posterior. Es orden que las claves se clasifiquen según su orden natural. Necesita tener un Comparador o hacer las teclas Objetos comparables. Para simular un comportamiento de mapa hash vinculado (el orden de iteración es el orden en el tiempo en el que se agregaron las entradas) implementé mis objetos clave para compararlos siempre para que sean mayores que otro objeto dado a menos que sea igual (lo que sea que sea para su objeto) ) Un mapa de hash vinculado sincronizado no fue suficiente porque como se indica en http://www.ibm.com/developerworks/java/library/j-jtp07233.html : "Los contenedores de colecciones sincronizadas, synchronizedMap y synchronizedList, a veces se llaman condicionalmente hilo -seguro- todas las operaciones individuales son seguras para subprocesos, pero las secuencias de operaciones donde el flujo de control depende de los resultados de operaciones previas pueden estar sujetas a carreras de datos. El primer fragmento en el Listado 1 muestra la expresión común poner-si-ausente - - si aún no existe una entrada en el Mapa, agréguela. Desafortunadamente, tal como está escrita, es posible que otro hilo inserte un valor con la misma clave entre el momento en que el método containsKey () retorna y el momento en que put () se llama al método. Si desea asegurarse de que se inserte exactamente una vez, debe envolver el par de instrucciones con un bloque sincronizado que se sincronice en el mapa m. "

Entonces, lo único que ayuda es un ConcurrentSkipListMap que es 3-5 veces más lento que un ConcurrentHashMap normal.


Collections.synchronizedMap(new LinkedHashMap())