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