vainolo と JB の回答はどちらも適切です。
1 つ追加します。それは、ワード カウントを格納する高度な並行データ構造を作成する方法の説明です。
vainolo が言ったように、ConcurrentSkipListMapは必要な基本的なデータ構造です。これは、並べ替えと同時実行の両方であるためです。それを有効に利用するには、ロックを行わないようにする必要があります。つまり、ロック、読み取り、書き込み、ロック解除のサイクルを含むパターンを避ける必要があります。これには 2 つの結果があります。1 つ目は、マップに新しい単語を配置する際にロックを使用しないことと、既存の単語のカウントをインクリメントする場合にロックを使用しないことです。
ConcurrentMap のputIfAbsentメソッドを使用して、マップに新しいものを安全に追加できます。ただし、それだけでは十分ではありません。使用するたびに潜在的な値を提供する必要があり、コストがかかる可能性があるからです。最も簡単な方法は、一種のダブルチェック ロック パターンを使用することです。最初に単純に既存の値を取得しようとし、存在しない場合は、putIfAbsent を使用して新しい値を追加します (単純にput を呼び出します。同時に put する 2 つのスレッド間で競合が発生する可能性があるためです)。
マップに整数を格納するのではなく、それ自体が整数を含むオブジェクトを格納することで、ロックを使用しないインクリメントを簡単に行うことができます。そうすれば、インクリメントされた値をマップに入れる必要はなく、すでにそこにあるオブジェクトをインクリメントするだけです。AtomicIntegerはこれに適した候補のようです。
それをまとめると、次のようになります。
public class WordCounts {
private final ConcurrentMap<String, AtomicInteger> counts
= new ConcurrentSkipListMap<String, AtomicInteger>();
public void count(String word) {
AtomicInteger count = getCount(word);
count.incrementAndGet();
}
private AtomicInteger getCount(String word) {
AtomicInteger count = counts.get(word);
if (count == null) {
AtomicInteger newCount = new AtomicInteger();
count = counts.putIfAbsent(word, newCount);
if (count == null) count = newCount;
}
return count;
}
}