问题描述
Java中的集合迭代不是线程安全的,即使您使用的是同步包装器(Collections.synchronizedMap(...)
)之一:
当遍历其任何集合视图时,用户必须手动在返回的地图上进行同步:
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()); }
对同步集合的其他调用是安全的,因为包装器类将它们包围在synchronized
块中,这些块将包装器集合用作其监视器:
public int size() {
synchronized( this ) {
return collection.size();
}
}
与collection
原始的收藏。这适用于集合/映射公开的所有方法,迭代方法除外。
映射的键集以相同的方式进行同步:同步的包装器根本不返回原始键集。相反,它返回集合原始键集的特殊同步包装器。条目集和值集也是如此。
解决方法
我了解像Hashtable这样的集合是同步的,但是有人可以向我解释它是 如何
工作的,在什么时候访问仅限于并发调用?例如,假设我使用了一些像这样的迭代器:
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()中并发循环尚未处理的项目,该怎么办?
谢谢你的帮助!