Kevin Bourrillionが正しいです。あなたが作成したマップの技術的理由は、スレッドセーフでないことです。使用しているマップがスレッドセーフであっても、テーブル操作はそうでないかもしれません。 Tables.newCustomTable
で使用されているStandardTable
、実装として私は、プットの例を挙げてみましょう:
public V put(R rowKey, C columnKey, V value) {
Map<C, V> map = backingMap.get(rowKey);
if (map == null) {
map = factory.get();
backingMap.put(rowKey, map);
}
return map.put(columnKey, value);
}
スレッドの安全性はmap == null
例取り扱いには危険にさらされます。つまり、2つ以上のスレッドがそのブロックに入り、columnKey
の新しいエントリを作成し、最後にbackingMap.put(rowKey, map)
を実行すると、backingMap
のcolumnKey
のエントリがオーバーライドされ、put
の操作が失われますスレッド。特に、マルチスレッド環境でのこの操作の結果は、非決定的です。これは、この操作がスレッドセーフではないと言うことに相当します。
このメソッドの正しい実装は次のようになります。
public V put(R rowKey, C columnKey, V value) {
ConcurrentMap<C, V> map = table.get(rowKey);
if (map == null) {
backingMap.putIfAbsent(rowKey, factory.get());
}
map = backingMap.get(rowKey);
return map.put(columnKey, value);
}
適切にスレッドセーフを取得するために、あなたがやってみたかったものと一緒にForwardingTable
実装を使用することが可能であるならば、私は現在調査していますConcurrentTable
。
しかし、正直に言うと、私はTable
のないスレッドセーフな実装が存在しない理由は、インタフェース自体がそのようなputIfAbsent
やreplace
など任意の並行処理構造を、提供していないということだと思います。
「並行表」の定義は何ですか? –
良い質問です。私の質問を別の方法で表現するには:ConcurrentMap>がそうでないように、それらのテーブルが爆発するでしょうか?そして、 "吹き飛ばす"という言い方をすると、無限ループに入り、例外をスローしたり、複数のスレッドを同時に読み書きしようとすると、通常のHashBasedTableが何をするかを決めることができます。 –