Envío de tareas: Runnable frente a Callable
Envíe tareas Runnable y Callable, y recupere los resultados mediante Future.
Envío de tareas: Runnable frente a Callable es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.
Runnable frente a Callable
Dos interfaces funcionales representan las tareas enviadas a ExecutorService:
- Runnable: no devuelve ningún valor y no puede declarar excepciones comprobadas
- Callable<V>: devuelve un resultado de tipo V y puede lanzar excepciones comprobadas
import java.util.concurrent.*;
// Runnable — no return value
Runnable r = () -> System.out.println("Running");
// Callable<Integer> — returns a value
Callable<Integer> c = () -> {
return 42; // or do computation
};submit(Runnable)
submit(Runnable) devuelve un Future<?>. Al llamar a get() sobre él, devuelve null, lo que confirma que la tarea ha terminado, o lanza una excepción si ha fallado.
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<?> future = pool.submit(() ->
System.out.println("Task done on " + Thread.currentThread().getName())
);
future.get(); // waits for completion; returns null
System.out.println("Task confirmed complete");
pool.shutdown();submit(Callable<V>)
submit(Callable) devuelve un Future<V>. Llame a future.get() para recuperar el resultado; la llamada bloquea hasta que finaliza.
ExecutorService pool = Executors.newFixedThreadPool(2);
Callable<Integer> sumTask = () -> {
int sum = 0;
for (int i = 1; i <= 100; i++) sum += i;
return sum;
};
Future<Integer> future = pool.submit(sumTask);
Integer result = future.get(); // blocks until done
System.out.println("Sum 1..100 = " + result); // 5050
pool.shutdown();Enviar varios Callable con invokeAll
invokeAll() envía una colección de Callable y devuelve una List de Futures; todos se completan antes de que el método retorne:
List<Callable<String>> tasks = List.of(
() -> "Result A",
() -> "Result B",
() -> "Result C"
);
ExecutorService pool = Executors.newFixedThreadPool(3);
List<Future<String>> futures = pool.invokeAll(tasks);
for (Future<String> f : futures) {
System.out.println(f.get());
}
pool.shutdown();invokeAny: primer resultado correcto
invokeAny() envía una colección de Callable y devuelve el resultado del primero que se completa correctamente, cancelando los demás:
List<Callable<String>> candidates = List.of(
() -> { Thread.sleep(200); return "Slow"; },
() -> { Thread.sleep(50); return "Fast"; },
() -> { Thread.sleep(100); return "Medium"; }
);
ExecutorService pool = Executors.newFixedThreadPool(3);
String winner = pool.invokeAny(candidates);
System.out.println("First: " + winner); // Fast
pool.shutdown();execute() frente a submit()
execute(Runnable) ejecuta la tarea y se olvida de ella: no devuelve ningún Future, y las excepciones se pierden a menos que añada un controlador de excepciones no capturadas. submit() envuelve la tarea en un Future y captura las excepciones para recuperarlas mediante get().
ExecutorService pool = Executors.newFixedThreadPool(2);
// execute: exception silently lost
pool.execute(() -> { throw new RuntimeException("Oops!"); });
// submit: exception captured in Future
Future<?> f = pool.submit(() -> { throw new RuntimeException("Oops!"); });
try {
f.get();
} catch (ExecutionException e) {
System.out.println("Caught: " + e.getCause().getMessage());
}
pool.shutdown();Callable con excepciones comprobadas
A diferencia de Runnable, Callable puede lanzar excepciones comprobadas, por lo que resulta natural usarlo para operaciones de E/S y de base de datos:
Callable<String> dbQuery = () -> {
// This compiles fine — checked exception is declared on Callable.call()
if (Math.random() < 0.5) throw new java.sql.SQLException("DB error");
return "row data";
};
Future<String> f = pool.submit(dbQuery);
try {
String data = f.get();
} catch (ExecutionException e) {
if (e.getCause() instanceof java.sql.SQLException) {
System.out.println("DB failed: " + e.getCause().getMessage());
}
}Paralelizar cálculos independientes
Use varios envíos de Callable para ejecutar cálculos independientes en paralelo:
ExecutorService pool = Executors.newFixedThreadPool(4);
Future<Long> sumFuture = pool.submit(() -> LongStream.rangeClosed(1,1_000_000).sum());
Future<Long> prodFuture = pool.submit(() -> LongStream.rangeClosed(1,20).reduce(1L, (a,b)->a*b));
long sum = sumFuture.get();
long prod = prodFuture.get();
System.out.println("Sum: " + sum + ", 20!: " + prod);
pool.shutdown();Agregación de resultados de Callable
Envíe muchas tareas y agregue los resultados cuando todas hayan terminado:
int N = 8;
ExecutorService pool = Executors.newFixedThreadPool(N);
List<Future<Integer>> futures = new ArrayList<>();
for (int i = 0; i < N; i++) {
final int chunk = i;
futures.add(pool.submit(() -> chunk * chunk)); // i^2
}
int total = 0;
for (Future<Integer> f : futures) total += f.get();
System.out.println("Sum of squares: " + total);
pool.shutdown();Tiempo de espera de Callable
Pase un tiempo de espera a future.get(timeout, unit) para evitar esperar indefinidamente:
Future<String> f = pool.submit(() -> {
Thread.sleep(5000); // slow task
return "done";
});
try {
String result = f.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.out.println("Task timed out");
f.cancel(true); // interrupt the task
} catch (ExecutionException e) {
System.out.println("Task failed: " + e.getCause());
}Prácticas recomendadas
Resumen de las prácticas recomendadas:
- Prefiera
submit()aexecute(): las excepciones se capturan - Use Callable cuando necesite un valor de retorno o excepciones comprobadas
- Llame siempre a
future.get()con un tiempo de espera - Use invokeAll para el procesamiento por lotes e invokeAny para quedarse con la primera respuesta
- Cierre siempre el grupo
Comprobación rápida
¿Cuál es la principal ventaja de Callable frente a Runnable?
Repaso: Runnable frente a Callable
Conceptos clave:
- Runnable: void, sin excepciones comprobadas; submit devuelve Future> null
- Callable: devuelve V y puede lanzar excepciones comprobadas; submit devuelve Future
- invokeAll: envía un lote y espera a que todas las tareas terminen
- invokeAny: devuelve el primer resultado correcto y cancela el resto
- Use siempre submit() para capturar excepciones
Preguntas frecuentes
¿La lección «Envío de tareas: Runnable frente a Callable» es gratis?
Sí — el texto completo de «Envío de tareas: Runnable frente a Callable» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Envío de tareas: Runnable frente a Callable»?
Envíe tareas Runnable y Callable, y recupere los resultados mediante Future. Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Java Academy?
No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «Envío de tareas: Runnable frente a Callable»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Java Academy?
Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- ExecutorService y tipos de grupos de hilos
- Envío de tareas: Runnable frente a Callable
- Future y gestión de errores
- ScheduledExecutorService para tareas recurrentes