The ThreadLocal Problem ThreadLocal has been the standard way to pass contextual data through a call chain without polluting method signatures since Java 1.2. Every Java developer has seen it used for things like: Web request context (user ID, correlation ID, tenant ID) Database transaction binding Security principal propagation Logging MDC (Mapped Diagnostic Context) Here is the classic pattern: public class RequestContext { // ThreadLocal stores one value per thread private static final ThreadLocal<String> CURRENT_USER = new ThreadLocal<>(); public static void set(String userId) { CURRENT_USER.
Continue reading »Concurrency
7 posts in this section
Structured Concurrency (JEP 505): Preview 5 — What Changed?
Note: JEP 505 is a preview feature in Java 25 (5th preview). Enable with --enable-preview. The API has been stable for several rounds and is expected to finalize in Java 26. The Problem with Unstructured Concurrency Classic Java concurrency with ExecutorService is unstructured: you submit tasks, and those tasks have no formal relationship with the code that submitted them. This causes three recurring problems: Problem 1: Partial failure leaves orphaned tasks ExecutorService exec = Executors.
Continue reading »CompletableFuture: Async Pipelines and Non-Blocking Composition
The Problem with Future<T> Fetching a product page on an e-commerce site requires at least three data sources: product details, live pricing, and inventory availability. Done sequentially, a 200 ms call to each service adds up to 600 ms. Done in parallel with a properly composed CompletableFuture pipeline, the wall-clock time drops to roughly the slowest of the three — around 200 ms. This article shows exactly how to build that pipeline and everything else you need to write robust async code in Java 8.
Continue reading »New APIs: Base64, StringJoiner, Spliterator, Files.lines, StampedLock, Nashorn
Base64 Before Java 8, Base64 encoding required a third-party library (Apache Commons Codec, Guava) or the internal sun.misc.BASE64Encoder class — an API that was never officially supported and was deliberately restricted from Java 9 onwards. Java 8 standardised encoding in java.util.Base64, which covers standard, URL-safe, and MIME variants and can wrap streams for large payloads. Java 8 added java.util.Base64 to the standard library. Three Encoders // Standard Base64 (RFC 4648) Base64.
Continue reading »Parallel Streams: ForkJoinPool, Spliterators, and When NOT to Parallelize
How Parallel Streams Work Parallel streams are one of Java 8’s most misused features. It is tempting to add .parallel() to any slow stream pipeline, but the performance characteristics are counterintuitive: parallel can make things slower for small data, and adding blocking I/O inside a parallel stream can stall the entire JVM. This article explains the mechanics, the cases where parallel genuinely helps, and the patterns to avoid. A parallel stream splits its source into sub-sequences, processes each sub-sequence on a separate thread, and merges the results.
Continue reading »Virtual Threads (JEP 444): A Million Threads Without the Pain
The Platform Thread Problem Every Java thread since Java 1.0 maps 1:1 to an OS thread. OS threads are heavy: Stack memory: 512 KB – 2 MB per thread (configurable with -Xss, default 512 KB on Linux) Context switch cost: ~1–10 μs per switch (kernel mode transition + cache invalidation) Hard limit: A 64-bit machine with 8 GB RAM can support roughly 8,000–16,000 OS threads before running out of stack memory This limit shapes how Java servers are built.
Continue reading »Spring Boot Virtual Threads: Benchmarks, Pitfalls, and When NOT to Use Them
Virtual Threads landed in Java 21 as a stable feature, and Spring Boot 3.2 added first-class support with a single property. The promise: write simple blocking code and get WebFlux-level throughput. The reality is mostly true — with some important exceptions. This article covers what Virtual Threads actually are, how to enable them in Spring Boot, real benchmark numbers, the three pitfalls that will silently destroy your performance, and a decision framework for when to use them (and when not to).
Continue reading »