同步集合

时间:2013-04-03 20:57:23

标签: java loops synchronized

由于c已经是同步集合,因此它是线程安全的。但为什么我们必须再次使用synchronized(c)进行迭代?真的很困惑。感谢。

“用户必须手动同步返回的内容 迭代时收集:

Collection c = Collections.synchronizedCollection(myCollection);
 ...
 synchronized(c) {
     Iterator i = c.iterator(); // Must be in the synchronized block
     while (i.hasNext()) {
         foo(i.next());
     }
}

不遵循此建议可能会导致非确定性行为。 “ http://docs.oracle.com/javase/6/docs/api/java/util/Collections

2 个答案:

答案 0 :(得分:10)

大多数synchronized集合实现可能会保证每个单个方法调用都是同步的。但迭代必然涉及多个单独的方法调用,因此您(同步集合的用户)必须自己在整个迭代中进行同步。

例如,如果您未在c上进行同步,则集合的内容可能会在i.hasNext()i.next()之间发生变化 - 甚至可能会从元素变为无效更多元素,在这种情况下i.next()会失败。

答案 1 :(得分:4)

使类上的所有方法单独同步不会使这些方法的聚合(在组中调用它们)是线程安全的。通过将Iterator包装在一个synchronized块中,您可以保护迭代器的特定实例,使其单独的方法被多个线程散布其他调用。

如果我在安全时拨打.add(),如果我需要多次拨打.add()来完成逻辑陈述,则无法保证其他人没有添加其他内容或删除某些内容我的.add()调用之间的其他操作,除非我阻止通过.add()(或任何其他方法)对表示集合的变量synchronizing调用其他所有内容。

Iterator对集合上的各个方法进行多次调用,它们都必须包含在单个synchronized块中,以使它们作为单个transaction排序执行。检查Iterator实现的源代码,你会明白我的意思。以下是List的源代码,它对底层实现进行多次单独调用,因此它们都需要由同一个线程以不间断的顺序执行才能确定。

  @Override
    public Iterator<A> iterator() {
        if (tail == null)
            return emptyIterator();
    return new Iterator<A>() {
        List<A> elems = List.this;
        public boolean hasNext() {
        return elems.tail != null;
        }
        public A next() {
                if (elems.tail == null)
                    throw new NoSuchElementException();
        A result = elems.head;
        elems = elems.tail;
        return result;
        }
        public void remove() {
        throw new UnsupportedOperationException();
        }
    };
    }

AbstractList.iterator()的{​​{3}}显示了进行多次调用的更复杂的逻辑。

更好的包装器将它们包装在Immutable个集合中,然后你保证没有其他任何东西可以改变调用之间的底层集合。