thread synchronizedmap safe current concurrent java caching concurrency hashmap

java - synchronizedmap - ConcurrentHashMap put vs putIfAbsent



thread safe hashmap (2)

Java Docs dice que, putIfAbsent es equivalente a

if (!map.containsKey(key)) return map.put(key, value); else return map.get(key);

Entonces, si la clave existe en el mapa, no actualiza su valor. ¿Es esto correcto?

¿Qué sucede si deseo actualizar un valor de clave basado en algunos criterios? Decir el tiempo de expiración, etc.

¿Sería esto una mejor opción para agregar y actualizar el caché?

public void AddToCache(T key, V value) { V local = _cache.putifabsent(key, value); if(local.equals(value) && local.IsExpired() == false){ return; } // this is for updating the cache with a new value _cache.put(key, value); }


Por lo tanto, no actualiza el valor de una clave. ¿es esto correcto?

Eso es correcto. Devolverá el valor actual que ya estaba en el mapa.

¿Sería esto una mejor opción para agregar y actualizar el caché?

Un par de cosas mejorarían su implementación.

1. No debe usar putIfAbsent para probar si existe, solo debe usarlo cuando desee asegurarse de que no exista y luego putIfAbsent . En su lugar, debe usar map.get para probar su existencia (o map.contains).

V local = _cache.get(key); if (local.equals(value) && !local.IsExpired()) { return; }

2. En lugar de put, querrás reemplazar, esto es porque una condición de carrera puede ocurrir donde el if puede ser evaluado como falso por dos o más hilos en los que uno de los dos (o más) hilos sobrescribirá las puts del otro hilo.

Lo que puedes hacer es reemplazar

Cuando todo está dicho y hecho, podría verse así

public void AddToCache(T key, V value) { for (;;) { V local = _cache.get(key); if(local == null){ local = _cache.putIfAbsent(key, value); if(local == null) return; } if (local.equals(value) && !local.IsExpired()) { return; } if (_cache.replace(key, local, value)) return; } }


Su código arrojará un NPE si la clave no estaba previamente en el mapa.

Aparte de eso, aunque esta es una idea razonable, no funcionará en un entorno " concurrente ". La razón por la que se agregó el método putIfAbsent() fue para que el mapa pudiera administrar la atomicidad de la operación utilizando cualquier soporte subyacente que esté utilizando para hacer que las operaciones sean seguras para la ejecución de subprocesos. En su implementación, 2 personas que llaman podrían terminar pisándose el uno al otro (el primero reemplaza un valor caducado con uno nuevo, y el segundo reemplaza inmediatamente el primero nuevo por uno nuevo).