Concurrent collections & CompletableFuture
Thread-safe collections from java.util.concurrent and chaining async operations.
Don't use plain HashMap across threads
A HashMap is not thread-safe. Concurrent puts from two threads can corrupt its internal structure — potentially causing an infinite loop (the classic Java 6 bug) or data loss. The java.util.concurrent package provides drop-in replacements:
Map<String, Integer> map = new ConcurrentHashMap<>();
List<String> list = new CopyOnWriteArrayList<>();
ConcurrentHashMap segments its buckets so reads are lock-free and writes lock only the relevant segment — much faster than Collections.synchronizedMap.
CopyOnWriteArrayList copies the entire array on each write — great for lists that are read often and written rarely (e.g. event listener registries).
BlockingQueue adds blocking put/take operations — ideal for producer-consumer pipelines:
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
// producer thread:
queue.put("item"); // blocks if the queue is full
// consumer thread:
String item = queue.take(); // blocks if the queue is empty
CompletableFuture enables chained asynchronous operations:
CompletableFuture.supplyAsync(() -> fetchUser(userId)) // runs on common pool
.thenApply(user -> user.getName()) // transform the result
.thenCompose(name -> sendEmail(name)) // chain another async op
.exceptionally(ex -> { log(ex); return null; }); // error handler
- supplyAsync — starts the pipeline on the ForkJoinPool common pool.
- thenApply — synchronous transform (like Stream.map).
- thenCompose — chains another CompletableFuture (like Stream.flatMap).
- thenAccept — terminal consumer that returns CompletableFuture<Void>.