並行性に戻ります。double checked locking
が機能するには、変数を として宣言する必要があることは明らかですvolatile
。しかし、以下のようにダブルチェックロックを使用するとどうなるでしょうか。
class Test<A, B> {
private final Map<A, B> map = new HashMap<>();
public B fetch(A key, Function<A, B> loader) {
B value = map.get(key);
if (value == null) {
synchronized (this) {
value = map.get(key);
if (value == null) {
value = loader.apply(key);
map.put(key, value);
}
}
}
return value;
}
}
通常のHashMapではなく、実際にConcurrentHashMapである必要があるのはなぜですか? すべてのマップの変更はブロック内で行われ、コードは反復子を使用しないため、技術的には「同時変更」の問題はありません。synchronized
API の使用ではなく概念について質問しているため、 putIfAbsent
/の使用を提案しないでください:) この API の使用がvsの主題に寄与しない限り。computeIfAbsent
HashMap
ConcurrentHashMap
2016-12-30 更新
この質問は、以下の Holger によるコメントによって回答されました。「HashMap.get
構造は変更されませんが、あなたの の呼び出しは変更されます。同期ブロックの外側で のput
呼び出しがあるため、操作の不完全な状態が同時に発生していることがわかります。」ありがとう!get
put