← SEARCHABLE ARCHIVE
Java · 2026-08-08

Java de los fundamentos al dominio — Lección 8

Ejecutar de forma segura subprocesos y operaciones asincrónicas

INTERACTIVE READING MODE →

Los artículos escritos en este blog fueron creados con el objetivo de enseñar. Además, la información del artículo puede ser incorrecta, así que tenga cuidado.

La ejecución de varias tareas simultáneamente puede aumentar el rendimiento, pero también aumenta la complejidad del estado compartido. Antes de decidir la cantidad de subprocesos, debe decidir quién cambiará el estado y cómo comunicar la finalización y el fracaso.

ExecutorService

ExecutorService executor = Executors.newFixedThreadPool(4);

try {
    Future<Integer> result = executor.submit(() -> loadScore());
    int score = result.get();
    System.out.println(score);
} finally {
    executor.shutdown();
}

Cuando se envía una tarea a ExecutorService, el ejecutor gestiona la creación y reutilización de subprocesos. Get de Future hace que el hilo actual espere hasta que se complete y también genera una excepción de tarea.

Proteger el estado compartido

private final Object lock = new Object();
private int gold;

public void addGold(int amount) {
    synchronized (lock) {
        gold += amount;
    }
}

Si varios subprocesos leen y escriben el mismo valor simultáneamente, es posible que se pierdan operaciones o que aparezcan estados intermedios. sincronizado permite que solo un hilo ejecute secciones que usan el mismo bloqueo a la vez.

Si el rango de bloqueo es demasiado amplio, la espera aumenta y la adquisición de varios bloqueos en diferentes órdenes puede provocar un punto muerto. Si es posible, es mejor reducir el propio estado compartido mutable.

CompletableFuture

CompletableFuture<Player> playerFuture =
    CompletableFuture.supplyAsync(this::loadPlayer, executor);

CompletableFuture<List<Item>> itemFuture =
    CompletableFuture.supplyAsync(this::loadItems, executor);

CompletableFuture<Void> all =
    CompletableFuture.allOf(playerFuture, itemFuture);

all.join();

Puede iniciar tareas independientes primero y combinar los pasos después de completarlas. Debe quedar claro en qué ejecutor se ejecuta el código y dónde se manejan las excepciones.

La concurrencia no hace que su código sea más rápido automáticamente. Se deben medir y gestionar el tamaño del trabajo, la latencia, el estado compartido y la terminación del ejecutor.