Every call you make is on a ConcurrentHashMap, and you still lost an update. How does a thread-safe collection get raced?
Thread safety composes per operation, not across operations. A get followed by a put is two atomic steps with a legal interleaving between them. You close the window by making the whole compound action one operation, such as compute or merge, or by holding a single lock across both steps.
Answer
Short answer
A ConcurrentHashMap lost update happens when the code performs a compound action as separate map calls. Each get, put or containsKey is thread-safe on its own, but another thread can interleave between them. Use compute, merge, putIfAbsent, replace, or one lock around the whole invariant so the read and write become one atomic decision.
Was this answer helpful?
Likely follow-ups
- What are the documented constraints on the function you pass to computeIfAbsent, and why do they exist?
- If two maps have to be updated together, what goes wrong with two locks and how do you avoid it?
- When is a compareAndSet retry loop preferable to a lock, and when does it become worse?
- How would you catch this class of defect in code review or CI rather than in production?
Related questions
- How would you design a thread-safe component, and why is adding synchronized to every method not a design?hardAlso on concurrency and locking7 min
- Two users click "book" on the last seat in your in-memory booking class at the same moment. Where does the lock go?mediumAlso on locking and concurrency5 min
- Two threads write to adjacent counters and throughput collapses. What is happening and how do you fix it?hardAlso on concurrency5 min
- Two users edit the same record and both save. What does EF Core do about it?mediumAlso on concurrency5 min