Unravel › Java concepts › Concurrency
Concurrent collections
Concurrent collections are safe to share between threads.
Learn these first
At a glance
A shared whiteboard with rules so people can write at once without erasing each other, and a conveyor belt that makes the packer wait when it is empty.
- 1ConcurrentHashMap locks only parts of the table, so threads rarely block each otherUse its atomic methods (putIfAbsent, computeIfAbsent, merge) for check-then-act logic.
- 2BlockingQueue implements the producer/consumer pattern: put waits when full, take waits when emptyA bounded queue gives natural back-pressure.
- 3CopyOnWriteArrayList copies the whole array on every change; it is good for rarely changed lists read very often (listener lists)
- Individually safe operations are not safe together: if (!map.containsKey(k)) map.put(k, v) is a race even on a ConcurrentHashMap; use putIfAbsent
- Since Java 8 ConcurrentHashMap uses compare-and-swap for empty buckets and locks only the head node of a bucket for updates
private final ConcurrentHashMap<String, LongAdder> hits = new ConcurrentHashMap<>();private final BlockingQueue<Job> queue = new ArrayBlockingQueue<>(100);public void count(String page) { hits.computeIfAbsent(page, k -> new LongAdder()).increment();}public void submit(Job job) throws InterruptedException { queue.put(job); // waits when the queue is full}- line 1 uses ConcurrentHashMap, the core of Concurrent collections
- line 2 uses BlockingQueue, the core of Concurrent collections
- line 8 waits when the queue is full
Read the full explanation (about 1 min)
Concurrent collections are safe to share between threads. ConcurrentHashMap allows many readers and writers, and a BlockingQueue lets producer and consumer threads hand work to each other.
A mental model
A shared whiteboard with rules so people can write at once without erasing each other, and a conveyor belt that makes the packer wait when it is empty.
How it works
ConcurrentHashMap locks only parts of the table, so threads rarely block each other. Use its atomic methods (putIfAbsent, computeIfAbsent, merge) for check-then-act logic.
BlockingQueue implements the producer/consumer pattern: put waits when full, take waits when empty. A bounded queue gives natural back-pressure.
CopyOnWriteArrayList copies the whole array on every change; it is good for rarely changed lists read very often (listener lists).
Going deeper
Individually safe operations are not safe together: if (!map.containsKey(k)) map.put(k, v) is a race even on a ConcurrentHashMap; use putIfAbsent. ConcurrentHashMap does not allow null keys or values. Iterators are weakly consistent: they never throw ConcurrentModificationException but may or may not show concurrent changes.
Under the hood
Since Java 8 ConcurrentHashMap uses compare-and-swap for empty buckets and locks only the head node of a bucket for updates. Blocking queues use a lock and conditions (or CAS for the linked variants).
Common mistakes
- Check-then-act with separate calls.
- Expecting null values in ConcurrentHashMap.
- Unbounded queues.
- CopyOnWriteArrayList for frequently modified data.
How Unravel recognises it
When you paste code, Unravel looks for these signs of concurrent collections. Spotting them yourself is a good habit when you read unfamiliar code:
- Types:
ConcurrentHashMapCopyOnWriteArrayListCopyOnWriteArraySetConcurrentLinkedQueueBlockingQueueLinkedBlockingQueueArrayBlockingQueuePriorityBlockingQueueConcurrentSkipListMapConcurrentLinkedDeque - Method calls:
synchronizedList()synchronizedMap()
Part of a learning path
- Concurrency fundamentals · previous: CompletableFuture
Related concepts
Builds on this
Frequently asked questions
What is Concurrent collections?
Concurrent collections are safe to share between threads. ConcurrentHashMap allows many readers and writers, and a BlockingQueue lets producer and consumer threads hand work to each other.
What are the most common mistakes with Concurrent collections?
Check-then-act with separate calls. Expecting null values in ConcurrentHashMap. Unbounded queues. CopyOnWriteArrayList for frequently modified data.
How can I see Concurrent collections in real code?
Paste your own Java into Unravel and it will point out where concurrent collections appears, explain how it works at the detail level you choose, and draw the flow of the code around it.