1 つのスレッドで以下を順次実行しています。
int サイズ = hashTable.size();
foreach.... in ... hasTable.values()
何かをする
私の質問は、foreach が size 回実行されますか? (その間に別のスレッドが要素を配置/削除したとしても?
1 つのスレッドで以下を順次実行しています。
int サイズ = hashTable.size();
foreach.... in ... hasTable.values()
何かをする
私の質問は、foreach が size 回実行されますか? (その間に別のスレッドが要素を配置/削除したとしても?
いいえ、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
いますが、反復は非常に高速です。
別のスレッドがhashTable
foreach の実行中に を変更すると、コードはConcurrentModificationException
.
Java HashTable size() に続いて values() はスレッドで安全ですか?
したがって、values()
安全でないのはメソッド呼び出しではありません。values()
に裏打ちされたイテレータを開くということですHashTable
。反復中にテーブルに変更が加えられた場合に例外をスローするのは反復子です。
私の質問は、foreach が size 回実行されますか? (その間に別のスレッドが要素を配置/削除したとしても?
前述のように、HashTable
反復中に変更された場合、 は例外をスローします。
HashTable
ほとんど廃止されました。の最新の並行バージョンを探している場合は、Java 5 で追加された HashMap
ものを使用する必要があります。余分な同期やコピーを行わずに反復処理を行う際に、バックグラウンドで変更が発生する場合を適切に処理します。ConcurrentHashMap
ConcurrentHashMap
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
...
}
あなたの例はスレッドセーフではありませんが、次のように簡単にスレッドセーフにすることができます:
synchronized(hashTable) {
int size = hashTable.size();
foreach.... in ... hasTable.values() {
// do something
}
}