在使用迭代器时解释集合的同步?

我知道像Hashtable这样的集合是同步的,但是有人可以向我解释它是如何工作的,以及在什么时候访问仅限于并​​发调用? 例如,假设我使用了一些像这样的迭代器:

Hashtable map = new Hashtable(); void dosomething1(){ for (Iterator<Map.Entry> i = map.entrySet().iterator(); i.hasNext();){ // do something } } void dosomething2(){ for (Iterator<Map.Entry> 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(); } 

有人可以解释一下我是否有任何陷阱让我从不同的线程中随机调用这些函数? 特别是迭代器如何进行同步,特别是在使用entrySet()时,它似乎也需要同步? 如果在其中一个循环正在进行时调用clear()会发生什么? 如果removedomething()删除了dosomething1()中并发循环尚未处理的项,该怎么办?

谢谢你的帮助!

即使您使用其中一个同步包装器( Collections.synchronizedMap(...) ),对Java中集合的迭代也不是线程安全的:

当迭代任何集合视图时,用户必须手动同步返回的地图:

 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 Collection Framework文档

对同步集合的其他调用是安全的,因为包装类用synchronized块包围它们,这些块使用包装器集合作为它们的监视器:

 public int size() { synchronized( this ) { return collection.size(); } } 

collection是原始集合。 这适用于集合/映射公开的所有方法,迭代内容除外。

映射的键集以同样的方式进行同步:同步包装器根本不返回原始键集。 相反,它返回集合的原始密钥集的特殊同步包装。 这同样适用于条目集和值集。