iterator.next()的线程安全性

anhgbhbe  于 2021-07-06  发布在  Java
关注(0)|答案(3)|浏览(721)

如果我有 Iterator 在多个线程之间共享,每个线程调用:

// Inside a thread
int myValue = iterator.next();

可能的结果是什么?
(忽略next()可能抛出nosuchelementexception的事实)如果迭代器是arraylist上的迭代器,是否有可能多个线程在 myValue 变量?
下面的代码是解决此问题的一种方法吗(除了使用这里描述的Java8流之外(在java中向多个线程传递一个列表迭代器)。

// Inside a thread
int myValue;
synchronized(iterator)
{
    myValue = iterator.next();
}
d8tt03nd

d8tt03nd1#

是不是多个线程在myvalue变量中可能以相同的值结束?
不能保证。
iterator 不是线程安全的,您应该在集合的对象上同步。

Iterator<String> iterator = obj.iterator();

synchronized (obj) {
    while (iterator.hasNext()) {
        int myValue = iterator.next();
        //...
    }
}
a0x5cqrl

a0x5cqrl2#

tldr公司;不要在线程之间共享迭代器!
考虑到迭代器在内容上循环的最常见用法,您可能会遇到以下代码段:

while(iterator.hasNext()) {
    Object nextItem = iterator.next();
}

现在考虑另一个线程执行完全相同操作的可能性。由于无法控制线程调度,因此在具有单个元素的迭代器上可能会发生以下情况:

Thread 1: hasNext? true
Thread 2: hasNext? true
Thread 1: next() //but if this was the last element...
Thread 2: next() //...this will throw NoSuchElementException

迭代器也可以支持 Iterator.remove() ,这会导致 ConcurrentModificationException 在共享集合上操作时。
我们能在不同的线程中得到相同的值吗?
以与上面类似的方式,考虑这个非常简单的迭代器实现(简化代码):

class SimpleIterator implements Iterator {
    ArrayList source;
    int currentIndex;
    hasNext() {
        return currentIndex<source.size();
    }
    next() {
         Object o = source.get(currentIndex);
         currentIndex++;
         return o;
    }
}

在这里,我们可能会得到:

Thread 1: get(currentIndex) //Object A
Thread 2: get(currentIndex) //also Object A
Thread 1: currentIndex++
Thread 2: currentIndex++  //you have skipped an element

答案是肯定的,但需要注意的是,这在很大程度上取决于实现。完全不去那里要安全得多。
重复:一般来说,您不应该在线程之间共享迭代器。

pbgvytdp

pbgvytdp3#

行为 List#iterator() 是不一致的 List 实现。 ArrayList , LinkedList ,将抛出 ConcurrentModificationException 如果在迭代过程中修改。要避免这种情况,请使用synchronizedlist()并锁定 List 在迭代过程中。 Vector 是由迪富尔特同步的,但是 Iterator 不是线程安全的。 CopyOnWriteArrayList ,我们可以迭代 List 即使在迭代过程中并发修改也很安全。

相关问题