Reading — step 1 of 7
Learn
~1 min readConcurrency
Direct Thread.start() is rarely used in modern Java. ExecutorService manages a thread pool; CompletableFuture chains async ops.
Executor types:
Executors.newFixedThreadPool(4) // bounded pool
Executors.newCachedThreadPool() // unbounded, reuses idle threads
Executors.newSingleThreadExecutor() // sequential (preserves order)
Executors.newScheduledThreadPool(2) // for delays / periodic tasks
Submit work, get a Future:
Future<Integer> f = exec.submit(() -> heavyCompute());
int result = f.get(); // BLOCKS until ready
int r2 = f.get(1, TimeUnit.SECONDS); // with timeout — throws TimeoutException
f.cancel(true); // best-effort cancellation
Future is limited — no chaining, no callbacks. CompletableFuture is the modern choice:
CompletableFuture<String> cf = CompletableFuture
.supplyAsync(() -> fetchUser(id))
.thenApply(user -> user.getName())
.thenCombine(
CompletableFuture.supplyAsync(() -> fetchSettings(id)),
(name, settings) -> render(name, settings))
.exceptionally(e -> "error: " + e.getMessage());
String result = cf.get(); // blocks at the end
Common methods:
supplyAsync(Supplier)— start an async computationthenApply(Function)— transform the resultthenCompose(Function)— chain a CompletableFuture-returning op (flatMap)thenCombine(other, BiFunction)— wait for two, combine resultsallOf(...)/anyOf(...)— fan-inexceptionally(Function)— recover from exceptionswhenComplete(BiConsumer)— side effect on success or failure
ALWAYS shut down executors:
exec.shutdown();
if (!exec.awaitTermination(30, TimeUnit.SECONDS)) {
exec.shutdownNow();
}
Most real Java services use thread pools sized by Runtime.getRuntime().availableProcessors() for CPU-bound work, or much larger for I/O-bound.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…