Is there a concurrent List in Java's JDK?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
The JDK does not provide a type literally named ConcurrentList, but it does provide several ways to make list-like access safe when multiple threads are involved. The correct choice depends less on the word "list" and more on the ratio of reads to writes, how you iterate, and whether order actually matters.
What the JDK Actually Offers
If you need a List that can be shared across threads, the two standard options are Collections.synchronizedList(...) and CopyOnWriteArrayList. They solve different problems.
Collections.synchronizedList(...) wraps an existing list and places a monitor around each individual operation. That means calls such as add, get, and remove are serialized. It is simple and often good enough for low to moderate contention.
The explicit synchronized (names) block around iteration is important. The wrapper makes single operations safe, but iteration is a multi-step activity. Without external synchronization, another thread may modify the list while you traverse it.
When CopyOnWriteArrayList Fits Better
CopyOnWriteArrayList takes the opposite tradeoff. Reads are cheap and iterators are stable because every write creates a new backing array. That sounds expensive, and it is, but only when writes are frequent. If the list is mostly read and only occasionally updated, this class is usually the cleanest option.
This loop does not throw ConcurrentModificationException because the iterator sees a snapshot. The new element appears in the list afterward, but not in the current traversal.
That behavior makes CopyOnWriteArrayList useful for listener registries, configuration snapshots, and routing tables that are read constantly and changed rarely.
Picking the Right Tool
A good rule is to start from access patterns.
Use Collections.synchronizedList(...) when writes are common, the list is not extremely hot, and you can control the locking discipline around compound actions.
Use CopyOnWriteArrayList when reads dominate and iteration must stay simple and safe even while other threads update the list.
If neither fits, the real answer may be that you do not need a List at all. Queues, maps, and sets have stronger concurrent support in java.util.concurrent. For example, producer-consumer pipelines usually want BlockingQueue, not a synchronized ArrayList.
Compound Operations Need Extra Thought
The biggest source of bugs is assuming that a thread-safe collection makes every sequence of operations atomic. It does not.
Consider this code:
Even with a synchronized wrapper, two threads can both observe that the element is absent and both add it. If you need a guarantee around the whole sequence, guard the entire check-and-act block with the same lock.
With CopyOnWriteArrayList, the same logical race exists. The class protects internal consistency, but it does not make your higher-level business rule atomic.
Performance Tradeoffs in Practice
Collections.synchronizedList(...) adds contention because all callers compete for one lock. Under heavy parallel access, that can become a bottleneck.
CopyOnWriteArrayList avoids lock-heavy iteration, but every mutation copies the whole array. If the list is large or modified often, memory churn and CPU overhead become obvious.
That is why there is no universal concurrent list in the JDK. Different workloads need different failure modes and performance characteristics.
Common Pitfalls
- Assuming the JDK has a
ConcurrentListtype. It does not; you choose from wrappers or specialized implementations. - Iterating over
Collections.synchronizedList(...)without synchronizing on the list. That leaves traversal exposed to concurrent changes. - Using
CopyOnWriteArrayListfor write-heavy workloads. The full-array copy on each mutation becomes expensive quickly. - Treating thread-safe methods as if they made compound business operations atomic. Wrap check-and-act sequences explicitly.
- Using a list when a queue, map, or set matches the workload better. The wrong abstraction creates avoidable contention.
Summary
- The JDK does not include a dedicated
ConcurrentListinterface or class. - '
Collections.synchronizedList(...)is appropriate when you want a normal list with explicit locking.' - '
CopyOnWriteArrayListis best when reads and iteration dominate over writes.' - Safe single operations do not automatically make multi-step logic atomic.
- Concurrent design starts with access patterns, not with class names.

