Vector, Hashtable and synchronizedMap
Understand why locking every method is not thread safety, and what to use instead.
Open this lesson in the learning hubKey points
Vector,HashtableandStacklock every method. They still work, but nothing new should use them.Collections.synchronizedMap(m)wraps a map so each call takes one lock — every thread queues behind it.- Per-method locking does not make a sequence safe:
getthenputis still a lost update. - To fix it yourself you must hold the lock across the pair:
synchronized (map) { ... }. - Iterating a synchronized wrapper needs that same manual block around the entire loop.
ConcurrentHashMaplocks one bin and offers atomicputIfAbsent,mergeandcompute.
Example
import java.util.*;
import java.util.concurrent.*;
public class Main {
static final int THREADS = 4;
static final int LOOPS = 5_000;
public static void main(String[] args) throws Exception {
Map<String, Integer> wrapped = Collections.synchronizedMap(new HashMap<>());
Map<String, Integer> guarded = Collections.synchronizedMap(new HashMap<>());
Map<String, Integer> concurrent = new ConcurrentHashMap<>();
ExecutorService pool = Executors.newFixedThreadPool(THREADS);
for (int t = 0; t < THREADS; t++) {
pool.submit(() -> {
for (int i = 0; i < LOOPS; i++) {
Integer old = wrapped.get("hits"); // atomic call
wrapped.put("hits", old == null ? 1 : old + 1); // atomic call, racy pair
synchronized (guarded) { // the whole pair is locked
Integer g = guarded.get("hits");
guarded.put("hits", g == null ? 1 : g + 1);
}
concurrent.merge("hits", 1, Integer::sum); // atomic on its own
}
});
}
pool.shutdown();
pool.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("expected : " + (THREADS * LOOPS));
System.out.println("synchronizedMap get+put: " + wrapped.get("hits") + " (usually short)");
System.out.println("synchronized (map) { } : " + guarded.get("hits") + " (you locked the pair)");
System.out.println("ConcurrentHashMap merge: " + concurrent.get("hits") + " (atomic per key)");
System.out.println();
System.out.println("Vector / Hashtable : one lock for the whole object, on every method");
System.out.println("legacy Stack : extends Vector - use ArrayDeque instead");
System.out.println("iterating a wrapper : needs synchronized (map) { for (...) } yourself");
}
}
Thread safety is a property of your operation, not of the collection you called it on.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Collections course, and every lesson in it is listed on the Collections contents page.