Java哈希表大小()后跟值(),线程中是否安全?
我在一个线程中按顺序执行以下操作: int size=hashTable.size() foreach。。。。在里面hasTable.values() 做点什么Java哈希表大小()后跟值(),线程中是否安全?,java,multithreading,thread-safety,hashtable,Java,Multithreading,Thread Safety,Hashtable,我在一个线程中按顺序执行以下操作: int size=hashTable.size() foreach。。。。在里面hasTable.values() 做点什么 我的问题是,foreach是否会执行大小倍?(即使另一个线程同时放置/删除一个元素?如果另一个线程在foreach执行期间修改哈希表,那么您的代码将抛出ConcurrentModificationException否,在方法级别上线程是安全的(多个线程可以随时调用任何方法)但是没有跨方法的同步。在两条指令之间,其他线程可能会添加/删除甚
我的问题是,foreach是否会执行大小倍?(即使另一个线程同时放置/删除一个元素?如果另一个线程在foreach执行期间修改
哈希表,那么您的代码将抛出ConcurrentModificationException
否,在方法级别上线程是安全的(多个线程可以随时调用任何方法)但是没有跨方法的同步。在两条指令之间,其他线程可能会添加/删除甚至清除哈希表
如果需要保持这种不变,请创建一个防御性副本(不必是线程安全的),并在该副本上执行size()
/循环:
Map<K, V> map = null;
synchronized(hashTable) {
map = new java.util.HashMap<>(hashTable);
}
map.size();
for(V v: map.values()) {
//...
}
但是,此解决方案意味着一次只能有一个线程执行循环(如果循环需要一些时间才能完成,则这可能成为瓶颈)。使用防御副本,每个线程都有自己的副本,多个线程可以同时循环。另一方面,如果哈希表
非常大,则此解决方案会更好(复制成本很高)但迭代非常快
Java哈希表大小()后跟值(),线程中是否安全
因此,不安全的不是values()
方法调用。而是在values()
上打开一个迭代器,该迭代器由HashTable
支持。如果在迭代过程中对表进行了修改,则迭代器会引发异常
我的问题是,foreach会被执行大小倍吗?(即使另一个线程同时放置/移除一个元素
如前所述,哈希表
如果在迭代时被修改,将抛出异常
HashTable
几乎已被弃用。如果您正在寻找一个现代的并发版本的HashMap
,那么您应该使用Java 5中添加的版本。ConcurrentHashMap
正确地处理在后台进行迭代时发生修改的情况,而无需额外的同步或cop莹:
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
...
}
ConcurrentHashMap=新的ConcurrentHashMap();
int size=map.size();
对于(…值:map.values()){
//如果其他线程添加或删除,则可能称为大于或小于大小
...
}
您的示例不是线程安全的,但可以很容易地使其成为线程安全的,如下所示:
synchronized(hashTable) {
int size = hashTable.size();
foreach.... in ... hasTable.values() {
// do something
}
}
这里有一个微妙之处。你将需要在哈希表上同步,同时将其传递到哈希表中。哈希表将在哈希表上迭代,这仍然会导致ConcurrentModificationException。也就是说,+1表示防御复制的想法。@JohnVint:+1,谢谢,你是对的!代码现在更难看了,但还是正确的。您觉得使用hashTable.clone()怎么样
相反?为什么要复制,为什么不将两个操作都包装在一个同步块中?@jtahlborn这个答案取决于我得到的单个迭代的成本,但如果你说我需要通过哈希表进行同步来进行复制。这会使线程安全吗?如果我使用同步(哈希表)这会阻止在其他线程中访问hasTable的方法?所以,如果是这样,我还不足以执行此同步(hashTable){int size=hashTable.size();foreach….in…hasTable.values()do something}
synchronized(hashTable) {
int size = hashTable.size();
foreach.... in ... hasTable.values() {
// do something
}
}