解释使用迭代器时集合的同步?
我知道像 Hashtable 这样的集合是同步的,但是有人可以向我解释它是如何工作的, 什么时候访问仅限于并发调用?例如,假设我使用了一些这样的迭代器:
I understand that collections like the Hashtable are synchronized, but can someone explain to me how it works, and at what point(s) access is restricted to concurrent calls? For example, let's say I use some iterators like this:
Hashtable<Integer,Integer> map = new Hashtable<Integer,Integer>();
void dosomething1(){
for (Iterator<Map.Entry<Integer,Integer>> i = map.entrySet().iterator(); i.hasNext();){
// do something
}
}
void dosomething2(){
for (Iterator<Map.Entry<Integer,Integer>> i = map.entrySet().iterator(); i.hasNext();){
// do something
// and remove it
i.remove();
}
}
void putsomething(int a, int b){
map.put(a,b);
}
void removesomething(int a){
map.remove(a);
}
var clear(){
map = new Hashtable<Integer,Integer>();
}
谁能解释一下我从不同线程随机调用这些函数是否有任何陷阱?特别是迭代器如何进行同步,尤其是当它使用 entrySet() 时,这似乎也需要同步?如果在其中一个循环正在进行时调用 clear() 会发生什么?如果 removesomething() 删除了一个尚未被 dosomething1() 中的并发循环处理的项目怎么办?
Can someone please explain if there are any pitfalls with me calling these functions at random from different threads? How does the iterator, in particular, do its synchronization, especially when it is using entrySet(), which would seem to also require synchronization? What happens if clear() is called while one of the loops is in progress? What if removesomething() removes an item that is not yet processed by a concurrent loop in dosomething1() ?
感谢您的帮助!
推荐答案
在 Java 中对集合的迭代不是线程安全的,即使您使用的是同步包装器之一(Collections.synchronizedMap(...)
):
Iteration over collections in Java is not thread safe, even if you are using one of the synchronized wrappers (Collections.synchronizedMap(...)
):
用户必须手动同步返回的迭代其任何集合视图时的映射:
It is imperative that the user manually synchronize on the returned map when iterating over any of its collection views:
Map m = Collections.synchronizedMap(new HashMap());
...
Set s = m.keySet(); // Needn't be in synchronized block
...
synchronized(m) { // Synchronizing on m, not s!
Iterator i = s.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
Java集合框架文档
对同步集合的其他调用是安全的,因为包装器类用 synchronized
块围绕它们,这些块使用包装器集合作为它们的监视器:
Other calls to synchronized collections are safe, as the wrapper classes surround them with synchronized
blocks, which use the wrapper collection as their monitor:
public int size() {
synchronized( this ) {
return collection.size();
}
}
collection
是原始集合.这适用于集合/映射公开的所有方法,迭代的东西除外.
with collection
being the original collection. This works for all methods exposed by a collection/map, except for the iteration stuff.
映射的密钥集以相同的方式同步:同步包装器根本不返回原始密钥集.相反,它返回集合的原始密钥集的特殊同步包装器.这同样适用于条目集和值集.
The key set of a map is made synchronized just the same way: the synchronized wrapper does not return the original key set at all. Instead, it returns a special synchronized wrapper of the collection's original key set. The same applies to the entry set and the value set.
相关文章