Card 07/ 09
All 9 cards
GotchaDifficulty: Advanced1 min
Why Synchronizing Every Method Did Not Make the Class Thread-Safe
A collection where every single method is synchronised, used by two threads, and two threads both take the last item.
List<Job> queue = Collections.synchronizedList(new ArrayList<>());
if (!queue.isEmpty()) {
Job next = queue.remove(0);
process(next);
}isEmpty() is synchronised and remove(0) is synchronised, and the gap between them is not. Two threads can both pass line 3 when one item is left, and the second remove throws IndexOutOfBoundsException.
Each method is atomic; the sequence is not. Synchronising every method makes each call safe on its own and says nothing about a caller that needs two of them to happen together.
Either hold the lock across the whole sequence, or use a method that does the whole thing in one step.
synchronized (queue) {
if (!queue.isEmpty()) { process(queue.remove(0)); }
}
// or, better
Job next = concurrentQueue.poll();
if (next != null) { process(next); }