2011-11-05 11 views
14

GuavaのTables.newCustomTable(Map, Supplier)メソッドは、スレッドセーフなマップが提供されている場合にスレッドセーフなテーブルを返しますか?例:バッキングマップがスレッドセーフである場合、Guavaテーブルスレッドは安全ですか?

public static <R, C, V> Table<R, C, V> newConcurrentTable() { 
    return Tables.newCustomTable(
     new ConcurrentHashMap<R, Map<C, V>>(), 
     new Supplier<Map<C, V>>() { 
     public Map<C, V> get() { 
      return new ConcurrentHashMap<C, V>(); 
     } 
     }); 
} 

このコードは実際に並行テーブルを返しますか?

+0

「並行表」の定義は何ですか? –

+0

良い質問です。私の質問を別の方法で表現するには:ConcurrentMap >がそうでないように、それらのテーブルが爆発するでしょうか?そして、 "吹き飛ばす"という言い方をすると、無限ループに入り、例外をスローしたり、複数のスレッドを同時に読み書きしようとすると、通常のHashBasedTableが何をするかを決めることができます。 –

答えて

19

docから: "複数のスレッドが同時にこのテーブルにアクセスし、スレッドの1つがテーブルを変更する場合は、外部と同期する必要があります。

並行バッキングコレクションでは不十分です。

+0

奇妙なことに、javadocの文章は私にこの質問をするよう促してくれました。しかたがない。ありがとう、ケビン。 –

16

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)を実行すると、backingMapcolumnKeyのエントリがオーバーライドされ、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のないスレッドセーフな実装が存在しない理由は、インタフェース自体がそのようなputIfAbsentreplaceなど任意の並行処理構造を、提供していないということだと思います。

+1

'StandardTable'実装を通して広範なブラウジングを行った後、私はスレッドセーフティを提供するために、最初から実装を作成するか、すべてのアクセスをロックするラッパーを提供するという2つの選択しかないという結論に達しました。 row()、column()またはcolumnMap()によって返されたビューがスレッドセーフではないため、メソッドのオーバーライドによってその動作を変更する方法がないためです。 – velocipedist

関連する問題