Missing actualizaciones con las cerraduras y ConcurrentHashMap

qué:

Tengo un escenario en el que tengo que mantener una Mapque puede ser poblada por múltiples hilos, cada modificación de su respectiva List(identificador de clave única / siendo el nombre de hilos), y cuando el tamaño de la lista para un hilo excede un tamaño de lote fijo, tenemos que persisten los registros a la base de datos.

clase agregador

private volatile ConcurrentHashMap<String, List<T>>  instrumentMap = new ConcurrentHashMap<String, List<T>>();
private ReentrantLock lock ;

public void addAll(List<T> entityList, String threadName) {
    try {
        lock.lock();
        List<T> instrumentList = instrumentMap.get(threadName);
        if(instrumentList == null) {
            instrumentList = new ArrayList<T>(batchSize);
            instrumentMap.put(threadName, instrumentList);
        }

        if(instrumentList.size() >= batchSize -1){
            instrumentList.addAll(entityList);
            recordSaver.persist(instrumentList); 
            instrumentList.clear();
        } else {
            instrumentList.addAll(entityList);  
        }
    } finally {
        lock.unlock();
    }

}

Hay un hilo más independiente que ejecute después de cada 2 minutos (usando la misma cerradura) a persistir todos los registros Map(para asegurarse de que tenemos algo persistió después de cada 2 minutos y el tamaño del mapa no se hace demasiado grande)

if(//Some condition) {
    Thread.sleep(//2 minutes);
    aggregator.getLock().lock();
    List<T> instrumentList = instrumentMap.values().stream().flatMap(x->x.stream()).collect(Collectors.toList());
    if(instrumentList.size() > 0) {
        saver.persist(instrumentList);
        instrumentMap .values().parallelStream().forEach(x -> x.clear());
        aggregator.getLock().unlock();
    }
}

Esta solución está funcionando bien en casi todos los escenarios para que hemos probado, excepto a veces vemos algunos de los registros desaparecieron, es decir, que no se conservan en absoluto, a pesar de que se han añadido a la fina mapa.

Mis preguntas son:

  1. ¿Cuál es el problema con este código?
  2. Es ConcurrentHashMapno es la mejor solución a este problema?
  3. ¿El Listque se utiliza con el ConcurrentHashMaptener un problema?
  4. ¿Debo usar el método de cálculo de ConcurrentHashMapaquí (no es necesario que pienso, como ReentrantLockya lo está haciendo el mismo trabajo)?
qué:

La respuesta proporcionada por @Slaw en los comentarios resolvieron el problema. Que estaban dejando el instrumentList instancia de escape en forma de acceso no sincronizado es decir / operaciones están pasando a través de lista sin ningún synchonization. La fijación de la misma al pasar la copia a otros métodos resolvieron el problema.

Siguiendo la línea de código es aquel en el que este problema estaba ocurriendo

recordSaver.persist (instrumentList); instrumentList.clear ();

Aquí estamos permitiendo la instrumentList ejemplo para escapar en forma no sincronizada es decir, se pasa a otra clase (recordSaver.persist) donde se iba a ser accionado en pero también estamos Borrar la lista en muy línea siguiente (en la clase Aggregator) y todo esto está ocurriendo en forma no sincronizada. Estado de lista no se puede predecir en protector de disco ... un error muy estúpido.

Hemos solucionado el problema pasando una copia clonada de instrumentList al método recordSaver.persist (...). De esta manera instrumentList.clear () no tiene efecto en la lista disponible en recordSaver para otras operaciones.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=138131&siteId=1
Recomendado
Clasificación