Card 08/ 09
Practice: Deciding Which Classes Are Thread-Safe
Four classes that all look guarded: find the gap in each one that is not.
A class is thread-safe only if every read and write of its shared state is protected by the same lock or an atomic operation, and every sequence that must be one operation is protected as a whole. For each of the four classes below, decide whether it is safe and, if not, name the gap, all four before you open the answer.
// 1
class A { private int n; synchronized void inc() { n++; } int get() { return n; } }
// 2
class B { private static int n; static synchronized void inc() { n++; }
synchronized int get() { return n; } }
// 3
class C { private final AtomicInteger n = new AtomicInteger();
void inc() { n.incrementAndGet(); } int get() { return n.get(); } }
// 4
class D { private final List<String> xs = Collections.synchronizedList(new ArrayList<>());
void addIfAbsent(String s) { if (!xs.contains(s)) { xs.add(s); } } }Which of the four are safe?
| Safe? | The gap | |
|---|---|---|
| 1 | No | get takes no lock, so it can read a value the last increment never published |
| 2 | No | inc locks the class and get locks the instance: two different locks |
| 3 | Yes | Both operations go through the atomic, which handles exclusion and visibility |
| 4 | No | contains and add are each atomic, and the sequence between them is not |
Number two is the one that looks most thorough. Every method carries the keyword, and no two threads are ever kept apart, because the locks are different objects.
Number four is the check-then-act shape again. Where a class needs two calls to be one operation, the safety has to live in whoever makes the calls.
← → move through sections and cards