iterator.next()的线程安全性

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

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

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

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

  1. // Inside a thread
  2. int myValue;
  3. synchronized(iterator)
  4. {
  5. myValue = iterator.next();
  6. }
d8tt03nd

d8tt03nd1#

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

  1. Iterator<String> iterator = obj.iterator();
  2. synchronized (obj) {
  3. while (iterator.hasNext()) {
  4. int myValue = iterator.next();
  5. //...
  6. }
  7. }
a0x5cqrl

a0x5cqrl2#

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

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

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

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

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

  1. class SimpleIterator implements Iterator {
  2. ArrayList source;
  3. int currentIndex;
  4. hasNext() {
  5. return currentIndex<source.size();
  6. }
  7. next() {
  8. Object o = source.get(currentIndex);
  9. currentIndex++;
  10. return o;
  11. }
  12. }

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

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

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

展开查看全部
pbgvytdp

pbgvytdp3#

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

相关问题