Memra

Callable, Future & ExecutorService

Returning values from threads and managing pools — the standard approach for production code.

Why ExecutorService instead of raw threads?

Creating a raw Thread per task is wasteful — threads are expensive OS resources. ExecutorService manages a thread pool: a fixed set of threads that pick up tasks from a queue.

Runnable tasks return nothing. Callable<V> is the equivalent that returns a value:

Callable<Integer> task = () -> {
    Thread.sleep(100);
    return 42;
};

Submitting and getting the result:

ExecutorService pool = Executors.newFixedThreadPool(4);
Future<Integer> future = pool.submit(task);  // returns immediately

// … do other work …

int result = future.get();   // BLOCKS until the task finishes
pool.shutdown();             // must call — prevents resource leak

Future API highlights:

| Method | Behaviour | |---|---| | get() | block until done; throws ExecutionException if the task threw | | get(3, TimeUnit.SECONDS) | block with a timeout; throws TimeoutException | | isDone() | non-blocking poll — true when finished | | cancel(true) | attempt to interrupt the running task |

shutdown() vs shutdownNow(): - shutdown() — no new tasks accepted; waits for in-flight tasks to finish. - shutdownNow() — interrupts running tasks and returns the queued ones.

Always call shutdown() in a finally block or use a try-with-resources shim so the pool is not left running forever.

NORMAL ~/memra/learn/java-from-zero/callable-future-executorservice utf-8 LF