- Ubicación: InMemoryBlueprintPersistence.java
- Descripción: HashMap no es thread-safe. Accesos concurrentes pueden causar:
- Corrupción de datos internos
- Bucles infinitos en operaciones de lectura
- Pérdida de datos durante redimensionamiento
- Impacto: Fallas catastróficas del sistema en entorno multiusuario
- Ubicación: saveBlueprint() método original
- Descripción: La secuencia "verificar si existe → insertar si no existe" no es atómica
- Escenario de falla:
Hilo A: containsKey(key) → false
Hilo B: containsKey(key) → false
Hilo A: put(key, blueprint)
Hilo B: put(key, blueprint) → SOBRESCRIBE sin excepción
- Resultado: Blueprints duplicados insertados sin detección
- Recursos compartidos: Map blueprints
- Operaciones: Verificación de existencia + inserción condicional
- Concurrencia: Múltiples threads pueden ejecutar simultáneamente
- Recursos compartidos: Map blueprints
- Operaciones: Verificación de existencia + actualización
- Riesgo: Similar check-then-act, pero menor impacto
- Métodos afectados: getBlueprint(), getAllBlueprints(), getBlueprintsByAuthor()
- Riesgo: Lecturas inconsistentes durante modificaciones concurrentes
- Cambio: HashMap → ConcurrentHashMap
- Beneficio: Thread-safety automático para operaciones básicas
- Rendimiento: Alta concurrencia de lectura, escritura segmentada
- Implementación:
Blueprint existing = blueprints.putIfAbsent(key, blueprint);
if (existing != null) {
throw new BlueprintPersistenceException(...);
}- Beneficio: Operación atómica que garantiza inserción única
- Rendimiento: Sin bloqueo global, solo sincronización localizada
- Métodos: get(), values(), iteration
- Garantía: ConcurrentHashMap proporciona vistas consistentes
- Beneficio: Lecturas sin bloqueo, alta escalabilidad
// MAL - Degrada rendimiento significativamente
public synchronized void saveBlueprint(Blueprint blueprint) {
// toda la lógica sincronizada
}Problemas:
- Serializa TODOS los accesos (lectura y escritura)
- Elimina beneficios de concurrencia
- Cuello de botella en alta concurrencia
// BIEN - Alto rendimiento
Blueprint existing = blueprints.putIfAbsent(key, blueprint);Beneficios:
- Sincronización solo cuando necesaria
- Lecturas concurrentes sin bloqueo
- Escalabilidad horizontal
- saveBlueprint(): Operación atómica putIfAbsent()
- getBlueprint(): Lectura thread-safe con ConcurrentHashMap
- getAllBlueprints(): Iteración segura con snapshot
- getBlueprintsByAuthor(): Filtrado thread-safe
- updateBlueprint(): put() atómico en ConcurrentHashMap
- Atomicidad: Cada operación individual es atómica
- Visibilidad: Cambios visibles inmediatamente entre threads
- Ordenamiento: Operaciones respetan happens-before relationships
// Test de carga concurrente
@Test
public void testConcurrentBlueprintCreation() {
ExecutorService executor = Executors.newFixedThreadPool(10);
CountDownLatch latch = new CountDownLatch(100);
for (int i = 0; i < 100; i++) {
executor.submit(() -> {
try {
// Intentar crear blueprints concurrentemente
persistence.saveBlueprint(new Blueprint("author", "name", points));
} catch (BlueprintPersistenceException e) {
// Esperado para duplicados
} finally {
latch.countDown();
}
});
}
latch.await();
// Verificar que solo se creó un blueprint
assertEquals(1, persistence.getAllBlueprints().size());
}La solución implementada garantiza:
- Thread-Safety Completa: Sin condiciones de carrera
- Alto Rendimiento: Lecturas concurrentes sin bloqueo
- Escalabilidad: Crece linealmente con número de threads
- Simplicidad: Sin complejidad de sincronización manual