8

Java Gurús,ConcurrentHashMap vs ReentrantReadWriteLock Mapa de encargo de acuerdo para la recarga de

Actualmente tenemos un HashMap<String,SomeApplicationObject> que está siendo leer con frecuencia y modificar de vez en cuando y estamos teniendo problemas que durante la modificación/recarga, Leer rendimientos de operación null que no es aceptable.

Para solucionar este tengo siguientes opciones:

A. Use ConcurrentHashMap

que se parece a la primera opción, pero la operación que estamos hablando es reload() - significa clear() seguido de replaceAll(). Por lo tanto, si Map se lee post clear() y pre replaceAll() devuelve nulo, lo que no es deseable. Incluso si yo synchronize esto no resuelve el problema.

B. Crear otra aplicación basada en ReentrantReadWriteLock

Dónde me gustaría crear adquirir Write Lock antes reload() operación. Esto parece más apropiado, pero creo que debe haber algo disponible para esto y no necesito reinventar la rueda.

¿Cuál es la mejor manera de salir?

EDIT ¿Alguna colección ya está disponible con esta característica?

+0

Sus mapas son efectivamente inmutables, lo que los convierte en un objetivo perfecto para su publicación a través de 'volátil'. –

+0

** Efectivamente inmutable ** lo siento, no entiendo 'inmutable' tan bien ... ¿Podría dar algunas pistas? – SiB

Respuesta

4

Parece que no está seguro de cómo se puede implementar lo que sugiere Peter Lawrey. Se podría tener este aspecto:

class YourClass { 
    private volatile Map<String, SomeApplicationObject> map; 

    //constructors etc. 

    public void reload() { 
     Map<String,SomeApplicationObject> newMap = getNewValues(); 
     map = Collections.unmodifiableMap(newMap); 
    } 
} 

No hay problemas de concurrencia porque:

  • El nuevo mapa se crea a través de una variable local, que por definición no se comparte - getNewValues no necesita ser sincronizado o atómica
  • la asignacion a map es atómica
  • map es volátil, lo que garantiza que otros hilos verán el cambio
8

Como va a volver a cargar el mapa, lo reemplazaría en una recarga.

Puede hacerlo utilizando un Mapa volátil, que reemplazará por completo cuando se actualice.

+0

¿podría explicar con más detalle? De alguna manera es difícil para mí razonar por qué esto funcionará. Entiendo que volátil garantizará la visibilidad, pero ¿cómo funcionará una operación compuesta como clear all replaceAll? Gracias. – Eugene

+0

Para reemplazar todo el mapa, todo lo que tiene que hacer es asignar el nuevo mapa a la referencia volátil anterior en su campo cuando haya creado la nueva copia. es decir, realmente está reemplazando todo, incluso el mapa en sí, no solo sus contenidos. –

5

Esto suena un montón como Guava'sCache, aunque en realidad depende de cómo se está poblando el mapa, y cómo calcular los valores. (Divulgación: Contribuyo a Guava).

La verdadera pregunta es si puede o no especificar cómo calcular su SomeApplicationObject dada la entrada String. Sólo en base a lo que nos ha dicho hasta ahora, podría ser algo como esto ...

LoadingCache<String, SomeApplicationObject> cache = CacheBuilder.newBuilder() 
    .build(
     new CacheLoader<String, SomeApplicationObject>() { 
     public SomeApplicationObject load(String key) throws AnyException { 
      return computeSomeApplicationObject(key); 
     } 
     }); 

Entonces, cada vez que quería reconstruir la memoria caché, que acaba de llamar cache.invalidateAll(). Con un LoadingCache, puede llamar al cache.get(key) y si aún no ha calculado el valor, se volverá a calcular. O tal vez después de llamar al cache.invalidateAll(), puede llamar al cache.loadAll(allKeys), aunque aún deberá poder cargar elementos individuales a la vez en caso de que surjan consultas entre invalidateAll y loadAll.

Si esto no es aceptable, si no puede cargar un valor individualmente, tiene que cargarlos todos a la vez, entonces seguiré adelante con el enfoque de Peter Lawrey, mantenga una referencia volatile a mapa (idealmente un ImmutableMap), vuelva a calcular todo el mapa y asigne el nuevo mapa a la referencia cuando haya terminado.

+0

SomeApplicationObject es una entidad que se precarga desde DB cuando se inicia la aplicación y se lee desde Map todo el tiempo ... Ocasionalmente System Admin puede volver a cargar los valores. – SiB