我在一个帖子中按顺序执行以下操作:
int size = hashTable.size();
foreach .... in ... hasTable.values()
做点什么
我的问题是foreach会执行大小时间吗? (即使另一个线程同时放置/删除元素?
答案 0 :(得分:6)
不,HashTable
在方法级别是线程安全的(多个线程可以随时调用任何方法),但是没有跨方法同步。在两条指令之间,其他线程可能会添加/删除甚至清除哈希表。
如果您需要保持这样的不变量,请制作防御性副本(不必是线程安全的)并在该副本上执行size()
/循环:
Map<K, V> map = null;
synchronized(hashTable) {
map = new java.util.HashMap<>(hashTable);
}
map.size();
for(V v: map.values()) {
//...
}
这里for-each是安全的,并且保证运行大小 - 次。同样如评论中所述,您只需在hashTable
上进行同步:
synchronized(hashTable) {
int size = hashTable.size();
for(V v: hashTable.values()) {
//...
}
}
然而,这个解决方案意味着一次只有一个线程可以执行循环(如果你的循环需要一些时间来完成,这可能会成为一个瓶颈)。使用防御性副本,每个线程都有自己的副本,并且几个线程可以同时循环。另一方面,如果hashTable
非常大(复制起来很昂贵),但是迭代非常快,这个解决方案 更好。
答案 1 :(得分:1)
如果另一个线程在执行foreach期间修改hashTable
,则代码将抛出ConcurrentModificationException
。
答案 2 :(得分:1)
Java HashTable size()后跟值()安全的线程?
所以不是values()
方法调用是不安全的。这是您在values()
上打开一个由HashTable
支持的迭代器。如果在迭代时对表进行了修改,则迭代器会抛出异常。
我的问题是foreach会执行大小时间吗? (即使另一个线程同时放置/删除元素?
如上所述,HashTable
如果在迭代它时被修改,则会抛出异常。
HashTable
几乎全部被弃用了。如果您正在寻找HashMap
的现代并发版本,那么您应该使用在Java 5中添加的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
...
}
答案 3 :(得分:1)
您的示例不是线程安全的,但它可以像这样轻松地保证线程安全:
synchronized(hashTable) {
int size = hashTable.size();
foreach.... in ... hasTable.values() {
// do something
}
}