Java 并行迭代与线程安全

Java 并行迭代与线程安全,java,multithreading,Java,Multithreading,我正在阅读B.Goetz Java并发的实践,现在我在读关于线程安全集合的部分。他描述了所谓的“隐藏迭代器”,它可能抛出ConcurrentModificationException。以下是他给出的示例: public class HiddenIterator{ @GuardedBy("this") private final Set<Integer> set = new HashSet<Integer>(); public synchroni

我正在阅读B.Goetz Java并发的实践,现在我在读关于线程安全集合的部分。他描述了所谓的“隐藏迭代器”,它可能抛出
ConcurrentModificationException
。以下是他给出的示例:

public class HiddenIterator{

    @GuardedBy("this")
    private final Set<Integer> set = new HashSet<Integer>();

    public synchronized void add(Integer i){ set.add(i); }
    public synchronized void remove(Integer i){ set.remove(i); }

    public void addTenThings(){
        Random r = new Random();
        for(int i = 0; i < 10; i++)
            add(r.nextInt());
        System.out.println("DEBUG: added ten elements to set " + set)
    }
}
公共类隐藏否认器{
@担保人(“本”)
私有最终集=新HashSet();
公共同步的void add(整数i){set.add(i);}
公共同步的void remove(整数i){set.remove(i);}
公共无效添加内容(){
随机r=新随机();
对于(int i=0;i<10;i++)
添加(r.nextInt());
System.out.println(“调试:在集合中添加了十个元素”+集合)
}
}
现在,很明显,
addTenThings()
可能抛出
ConcurrentModificationException
,因为打印
set
的内容需要迭代它。但他提出了以下处理建议:

如果HiddenIterator使用synchronizedSet包装哈希集, 封装同步后,不会发生这种错误


我不太明白。即使我们将
set
包装到一个同步包装器中,该类仍将保持
NotThreadSafe
。他是什么意思?

这是因为
集合。synchronizedSet
同步每个方法,包括
到字符串
。事实上,如果您试图手动迭代包装的集合,您可能会得到
ConcurrentModificationException
,因此您必须自己同步手动迭代。但是进行隐藏迭代的方法已经做到了,所以您至少不必担心这一点。以下是来自JDK源代码的相应代码:

public String toString() {
    synchronized (mutex) {return c.toString();}
}

在这里,
mutex
在包装类的构造函数中被初始化为
this
,因此它基本上是
synchronized(this)

他意味着不再发生ConcurrentModificationException。为什么你认为反过来是正确的?同步包装将自动同步(线程安全)添加到任意集合是的,
synchronizedSet
的迭代器不是线程安全的,需要手动同步。请阅读这里的帖子:@AadityaGavandalkar,这正是我所说的:手动迭代需要手动同步。但是做迭代的收集方法会同步它,这样你就不必自己做了。是的,我知道。我只是在评论,并没有强调这是一个错误:)