これを行う唯一の方法は、ロックを使用することです。最初にチェックを使用することで、この影響を最小限に抑えることができます。
if(!map.containsKey("John"))
synchronized(map) {
if(!map.containsKey("John"))
map.put("John", new Person("John"));
}
ロックが必要な理由は、他のスレッドが同じオブジェクトを同時に追加しようとするのを防ぐために、Personを作成する間マップを保持する必要があるということです。ConcurrentMapは、このようなブロッキング操作を直接サポートしていません。
特定のキーへのロックを最小限に抑える必要がある場合は、次のようにすることができます。
ConcurrentMap<String, AtomicReference<Person>> map = new ConcurrentHashMap<String, AtomicReference<Person>>();
String name = "John";
AtomicReference<Person> personRef = map.get(name);
if (personRef == null)
map.putIfAbsent(name, new AtomicReference<Person>());
personRef = map.get(name);
if (personRef.get() == null)
synchronized (personRef) {
if (personRef.get() == null)
// can take a long time without blocking use of other keys.
personRef.set(new Person(name));
}
Person person = personRef.get();