Iterable java列表循环并发问题

Iterable java列表循环并发问题,java,concurrency,Java,Concurrency,我有几个案例需要设置一个列表,然后以循环方式对它们进行迭代。我对多线程比较陌生,所以我在学习的过程中不断学习 今天我开始遇到一些并发问题 Exception in thread "LogThing: 25" Exception in thread "LogThing: 27" Exception in thread "LogThing: 21" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.che

我有几个案例需要设置一个
列表
,然后以循环方式对它们进行迭代。我对多线程比较陌生,所以我在学习的过程中不断学习

今天我开始遇到一些并发问题

Exception in thread "LogThing: 25" Exception in thread "LogThing: 27" Exception in thread "LogThing: 21" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
    at com.google.common.collect.Iterators$2.next(Iterators.java:418)
    at com.example.my.RoundRobinIterable.getNext(RoundRobinIterable.java:22)
    at com.example.my.EpsSendingStrategy.run(EpsSendingStrategy.java:22)
    at java.lang.Thread.run(Thread.java:745)
现在,RoundRobbinitable非常简单

import java.util.Iterator;
import java.util.List;

import com.google.common.collect.Iterables;

public class RoundRobinIterable<T> {
  private final Iterator<T> elements;

  public RoundRobinIterable(final List<T> elements) {
    this.elements = Iterables.cycle(elements).iterator();
  }

  public synchronized T getNext() {
    return this.elements.next();;
  }

}

编辑2:我也尝试了同样的同步,但这也是一个失败。还有一些更深层次的东西我还不理解。

正如javadoc中提到的:-

但您正在将同步列表传递给guava,如下所示:-

this.elements = Iterables.cycle(elements).iterator();
它在调用
.iterator()
时不使用同步。此外,它还可以在不受您控制的时间调用它(比如在您修改它时)


虽然这个答案可能为您指明了正确的方向,但等待某人(我从未使用过番石榴)给出更明确的答案可能是值得的。

ConcurrentModificationException被抛出,因为您在列表上迭代,而一些线程将元素添加到列表中

您正在使用Collections.synchronizedList,其中添加和删除方法由列表锁同步。要禁止其他人在使用迭代器迭代列表时向列表中添加内容,您必须像这样锁定该列表

synchronized(list){
Iterator i = list.iterator(); 
      while (i.hasNext()){
        //do something
  }
}
您没有这样做,您正在同步getNext方法,但没有使用列表锁,并且仅在调用next()方法时进行同步,这是不够的

 public synchronized T getNext() {
    return this.elements.next();;
  }
如果您想使用您的模式,您必须在RoundRobinitable中创建列表的副本

import java.util.Iterator;
import java.util.List;

import com.google.common.collect.Iterables;

public class RoundRobinIterable<T> {
  private final Iterator<T> elements;

  public RoundRobinIterable(final List<T> elements) {
    List<T> copyOfElements = new ArrayList<>(elements);
    this.elements = Iterables.cycle(copyOfElements).iterator();
  }

  public synchronized T getNext() {
    return this.elements.next();;
  }
}
import java.util.Iterator;
导入java.util.List;
导入com.google.common.collect.Iterables;
公共类roundrobinitable{
私有最终迭代器元素;
公共RoundRobinitable(最终列表元素){
List copyOfElements=新的ArrayList(元素);
this.elements=Iterables.cycle(copyofeelements.iterator();
}
公共同步T getNext(){
返回此.elements.next();;
}
}

现在,在您迭代列表时,没有人可以将元素添加到复制的列表中,但是在创建RoundRobinitable后,您将无法获得添加到原始列表中的元素。如果您希望获得稍后添加的元素,那么最好使用列表以外的其他内容。例如,ConcurrentLinkedQueue。

我们可以看到
EpsSendingStrategy
?@JacobG。我已经包括在内了。它扩展了具有可写性的SendingStrategy,这很有趣。我仍然不明白为什么该方法上的同步没有停止问题,但它确实给了我一些可以继续的东西。@buzzsawdog-sync-on
getNext()
方法?调用
.iterator()
怎么样?这似乎不是同步的。在最后一点,我根据我所做的研究重新思考了我正在做什么。由于缺乏经验,我做出了决定;-)我将尝试其他方法,如果不起作用,请回到您的想法。
 public synchronized T getNext() {
    return this.elements.next();;
  }
import java.util.Iterator;
import java.util.List;

import com.google.common.collect.Iterables;

public class RoundRobinIterable<T> {
  private final Iterator<T> elements;

  public RoundRobinIterable(final List<T> elements) {
    List<T> copyOfElements = new ArrayList<>(elements);
    this.elements = Iterables.cycle(copyOfElements).iterator();
  }

  public synchronized T getNext() {
    return this.elements.next();;
  }
}