Good Code
The good version uses a concurrent map and makes the atomic operation explicit with computeIfAbsent.
Lesson 08
Use concurrent primitives for shared state so check-then-act races do not appear under load.
public final class ProfileCache {
private final ConcurrentMap<UserId, UserProfile> profiles = new ConcurrentHashMap<>();
private final UserService users;
public UserProfile get(UserId id) {
return profiles.computeIfAbsent(id, users::loadProfile);
}
}public class ProfileCache {
private final Map<String, UserProfile> profiles = new HashMap<>();
public UserProfile get(String id) {
if (!profiles.containsKey(id)) {
profiles.put(id, users.loadProfile(id));
}
return profiles.get(id);
}
}The good version uses a concurrent map and makes the atomic operation explicit with computeIfAbsent.
The bad version uses a shared HashMap and a check-then-put sequence. Two threads can compute the same value, corrupt the map, or observe inconsistent state.