En mi aplicación, me gustaría tener un caché que se actualice diariamente mediante una operación costosa (por ejemplo, obtener de forma remota y computar localmente). La idea es todos los días, buscará y calculará el caché más reciente para hoy. Y en cualquier momento de hoy, cualquier subproceso debería poder leer/escribir en el caché diario. Y está bien servir los datos antiguos cuando la costosa operación se ejecuta a diario y no debería bloquear ninguna solicitud en ningún momento.
He escrito un código simple para ilustrar la idea, pero no estoy seguro de si es la mejor práctica o si es correcta en términos de subprocesos múltiples. Por ejemplo,
volatile ?¡Cualquier sugerencia será muy apreciada!
public class DailyCache { private volatile ConcurrentHashMap<String, String> cache; public DailyCache() { cache = expensiveCalculation(); Executors.newScheduledThreadPool(1) .scheduleAtFixedRate(() -> cache = expensiveCalculation(), 1, 1, TimeUnit.DAYS); } public String get(String key) { return cache.get(key); } public void put(String key, String value) { cache.put(key, value); } public ConcurrentHashMap<String, String> expensiveCalculation() { // an expensive operation to fetch the cache for today } }Para responder tu pregunta:
P: ¿es "la mejor práctica"?
No hay mejores prácticas . Si aún no lo ha hecho, tómese el tiempo para leerlo.
Esta pregunta no tiene respuesta... y ni siquiera tiene sentido.
Sugerencia: es hora de eliminar las "mejores prácticas" de su vocabulario... y comenzar a cuestionar la sabiduría de las personas que le dicen que algo es "mejores prácticas".
P: ¿Se requiere
volatile?
Quizás. Depende de si es posible que cambie la referencia en cache .
volatile .volatile . Pero en ese caso deberías declarar la variable como final . Si lo hace, entonces el JLS garantiza que todos los subprocesos verán el valor correcto para la variable. En su código, parece que está asignando periódicamente un nuevo valor al cache . Si es así, debe ser volatile o necesita alguna otra forma de asegurarse de que todos los subprocesos de trabajo vean el valor de cache actualizado. (Hay otras formas... pero esto empieza a oler a optimización prematura).
P: ¿Qué sucederá si finaliza una reasignación de caché en medio de un get o put?
Si la llamada get o put comienza antes de la asignación, definitivamente operarán en el caché anterior. Si no, no lo es, dependerá de si la recuperación de la cache se produce antes o después de la asignación. Eso es impredecible.
Hay otra cosa que no pareces haber considerado. Tu dices:
Y está bien servir los datos antiguos cuando la costosa operación se ejecuta a diario y no debería bloquear ninguna solicitud en ningún momento.
Pero no ha dicho si está bien (o no) que el caché anterior se actualice mientras se construye el nuevo caché. Por ejemplo, considere esta secuencia de eventos:
Ahora tenemos la aplicación ejecutándose con el nuevo caché, pero el nuevo caché contiene un valor 1 para la clave 1 que es más antiguo que el valor utilizado más recientemente (valor 2).
Si eso rompe su aplicación, entonces necesita una forma de resolverlo. Habrá formas... pero dependerá de aspectos de la lógica de su aplicación que no haya mencionado. Por ejemplo, los escenarios en los que los subprocesos de aplicaciones regulares put operaciones de almacenamiento en caché.