Concurrency

Concurrent Collections

ConcurrentHashMap, CopyOnWriteArrayList, ConcurrentSkipListMap, and the blocking queues replace lock-wrapped collections with data structures designed for concurrency — atomic compound operations included.
  • ConcurrentHashMap: fine-grained locking per bin; reads never block; use compute*/merge for atomic updates
  • Its iterators are weakly consistent — no ConcurrentModificationException, no snapshot either
  • CopyOnWriteArrayList: copies the array per write — perfect for read-mostly listener lists
  • BlockingQueue (ArrayBlockingQueue, LinkedBlockingQueue) = producer-consumer with built-in backpressure
  • ConcurrentSkipListMap/Set: the concurrent sorted alternatives
  • size()/isEmpty() are estimates under concurrency — design so you don't need exact answers
Atomic compound operations
ConcurrentHashMap<String, LongAdder> hits = new ConcurrentHashMap<>();

// check-then-act, made atomic by the map itself:
hits.computeIfAbsent(page, k -> new LongAdder()).increment();

ConcurrentHashMap<String, Integer> stock = new ConcurrentHashMap<>();
stock.merge(sku, -1, Integer::sum);              // atomic read-modify-write
stock.putIfAbsent(sku, 0);

The whole point over Collections.synchronizedMap: compound actions (putIfAbsent, computeIfAbsent, merge, replace(k, old, new)) execute atomically inside the map, so callers don't need a lock spanning two calls (Thread Safety). Throughput scales because writers contend per-bin (CAS + per-bin locks since Java 8), and readers proceed without any locking (volatile reads).

Producer–consumer with a BlockingQueue (JCiP ch. 5)
BlockingQueue<Task> queue = new ArrayBlockingQueue<>(1024);   // BOUNDED: backpressure

// producer                              // consumer (each in its own thread)
queue.put(task);                          Task t = queue.take();   // both block politely

// with timeouts at the edges:
if (!queue.offer(task, 100, MILLISECONDS)) shedLoad();

A bounded blocking queue is the standard safe-publication conveyor and the standard backpressure valve: producers outpacing consumers get slowed instead of ballooning memory (Scalability Patterns). SynchronousQueue (zero capacity, direct handoff) and LinkedTransferQueue serve thread-pool internals; DelayQueue schedules; Deque + work-stealing powers ForkJoin.

Sources
  • Java Concurrency in PracticeCh. 5 — Building Blocks
  • Core Java, Volume I: Fundamentals (13th ed.)Ch. 10.6 — Thread-Safe Collections
  • Effective Java (3rd ed.)Item 81