0

1 つのスレッドで以下を順次実行しています。

int サイズ = hashTable.size();

foreach.... in ... hasTable.values()

何かをする

私の質問は、foreach が size 回実行されますか? (その間に別のスレッドが要素を配置/削除したとしても?

4

4 に答える 4

6

いいえ、HashTableメソッド レベルではスレッド セーフです (複数のスレッドが任意のメソッドをいつでも呼び出すことができます) が、メソッド間の同期はありません。2 つの命令の間に、他のスレッドがハッシュテーブルを追加/削除したり、クリアしたりする可能性があります。

そのような不変性を維持する必要がある場合は、防御的なコピーを作成し (スレッドセーフである必要はありません)、size()そのコピーに対して /loop を実行します。

Map<K, V> map = null;
synchronized(hashTable) {
  map = new java.util.HashMap<>(hashTable);
}
map.size();
for(V v: map.values()) {
  //...
}

ここで for-each は安全であり、size-times の実行が保証されています。また、コメントに記載されているように、同期することができますhashTable

synchronized(hashTable) {
  int size = hashTable.size();
  for(V v: hashTable.values()) {
    //...
  }
}

ただし、この解決策は、一度に 1 つのスレッドしかループを実行できないことを意味します (ループの完了に時間がかかる場合、これがボトルネックになる可能性があります)。防御的コピーでは、各スレッドが独自のコピーを持ち、複数のスレッドが同時にループできます。一方、このソリューション、サイズが非常に大きい (コピーに費用がかかる)場合に適してhashTableいますが、反復は非常に高速です。

于 2012-08-29T17:24:17.727 に答える
1

別のスレッドがhashTableforeach の実行中に を変更すると、コードはConcurrentModificationException.

于 2012-08-29T17:23:00.053 に答える
1

Java HashTable size() に続いて values() はスレッドで安全ですか?

したがって、values()安全でないのはメソッド呼び出しではありません。values()に裏打ちされたイテレータを開くということですHashTable。反復中にテーブルに変更が加えられた場合に例外をスローするのは反復子です。

私の質問は、foreach が size 回実行されますか? (その間に別のスレッドが要素を配置/削除したとしても?

前述のように、HashTable反復中に変更された場合、 は例外をスローします。

HashTableほとんど廃止されました。の最新の並行バージョンを探している場合は、Java 5 で追加された HashMapものを使用する必要があります。余分な同期やコピーを行わずに反復処理を行う際に、バックグラウンドで変更が発生する場合を適切に処理します。ConcurrentHashMapConcurrentHashMap

ConcurrentHashMap<...> map = new ConcurrentHashMap<...>();
int size = map.size();
for (... value : map.values()) {
    // may be called more or less than size if other threads add or delete
    ...
}
于 2012-08-29T17:44:35.370 に答える
1

あなたの例はスレッドセーフではありませんが、次のように簡単にスレッドセーフにすることができます:

synchronized(hashTable) {
  int size = hashTable.size();
  foreach.... in ... hasTable.values() {
    // do something
  }
}
于 2012-08-29T18:07:14.447 に答える