java · level 3 · unit 5 · lesson 4
- meet it
- guess first
- your turn
- fix it
- nailed it
Tap a green word if you get lost.
meet it
A is a map, one change at a time.
A plain HashMap is not thread-safe: two threads writing at once can lose entries or tangle its insides. A ConcurrentHashMap is built for sharing. Each single call, like put or get, is safe however many threads use it.
Two calls together are not safe. counts.put(word, counts.getOrDefault(word, 0) + 1) is : another thread can change the count between the read and the write. Use one call instead: adds 1, or starts at 1, atomically.
A ConcurrentHashMap keeps no order. For a report, copy it into a TreeMap once the threads have finished: new TreeMap<>(counts).
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
public class Main {
static void tally(Map<String, Integer> counts, List<String> words) {
for (String word : words) {
counts.merge(word, 1, Integer::sum);
}
}
public static void main(String[] args) throws InterruptedException {
Map<String, Integer> counts = new ConcurrentHashMap<>();
List<String> pageOne = List.of("to", "be", "or", "not", "to", "be");
List<String> pageTwo = List.of("that", "is", "the", "question");
Thread a = new Thread(() -> tally(counts, pageOne));
Thread b = new Thread(() -> tally(counts, pageTwo));
a.start();
b.start();
a.join();
b.join();
System.out.println(new TreeMap<>(counts));
}
} Integer::sum is the rule merge uses to combine the old count with the new 1.
guess first
Two ways to merge. What will this show?
Guess before you run it. Wrong guesses are how you learn, and nothing is marked.
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
public class Main {
public static void main(String[] args) {
Map<String, Integer> stock = new ConcurrentHashMap<>();
stock.merge("apples", 5, Integer::sum);
stock.merge("pears", 2, Integer::sum);
stock.merge("apples", 3, Integer::sum);
stock.merge("pears", 4, Math::max);
System.out.println(new TreeMap<>(stock));
}
}
your turn
Your turn. Count the cafe orders.
On line 8, count each order with merge, adding 1 each time.
output
press run to see what happens
fix it
The running log forgets earlier runs. Can you fix it?
output
press run to see what happens
- Ana ran 30 and 20 minutes, but the map shows only her last run. What does line 7 do to an old value?
putreplaces whatever was there. These minutes need adding to the old total.- Change line 7 to
minutes.merge(runner, run, Integer::sum);, then run.
nailed it
your threads can share one map safely. :D
ConcurrentHashMapmakes every single call thread-safe.- Check-then-act across two calls is a race. Use one call.
mergeadds to the old value, or starts a new one.
new words in your collection
- ConcurrentHashMap
- thread-safe
- check-then-act
- merge
This lesson isn’t saved. A free account remembers every lesson you finish.