ConcurrentModificationException迭代列表但不修改它

时间:2018-04-17 10:48:29

标签: java java-8 jmeter java-stream concurrentmodification

我正在使用 JMeter 运行我的应用程序进行负载测试,并在(我认为)不应该来的情况下获取ConcurrentModificationException。这种情况仅发生在少数情况下,而不是全部。

我有一个ArrayList,它是一个类变量,通过方法添加元素。稍后在准备列表后调用的另一个方法中,使用stream进行迭代,并使用一些过滤器准备本地arraylist ,如下所示

...
//class variable getting elements from a separate method
List<String> myGlobalList = new ArrayList(); 
...

public String returnValue(String _value){
  List myLocalList = new ArrayList();
  myGlobalList.stream().filter(ele -> {
    ele = ele.replaceAll("\\[(.*?)\\]", "$1");

    String[] strArr = ele.split(",");
    for(String sArr : strArr) {
      if(sArr.contains(_value)){
        System.out.println("sArr ---- > "+sArr);
        myLocalList.add(sArr);
        return true ;
      }
    }
    return false;
  }).findFirst();

  return myLocalList.size()>0 ? myLocalList.get(0): null;
}

findFirst()方法仅在加载时抛出ConcurrentModificationException(不是针对每个请求)。

无法弄清楚它为什么会发生。 我是否遗漏了任何密钥?如何修改此代码以避免在所有情况下出现此异常?

更新

以下是来自异常的堆栈跟踪的片段

java.util.ConcurrentModificationException
at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1353)
at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464)
at com.pkg.MyClass.returnValue(MyClass.java:501)

1 个答案:

答案 0 :(得分:0)

您是否需要获取列表中的第一个字符串?为什么不在不使用List的情况下获取它:

  public String returnValue(String _value){   
  String findFirst = myGlobalList.stream().filter(ele -> {
    ele = ele.replaceAll("\\[(.*?)\\]", "$1");

    String[] strArr = ele.split(",");
    for(String sArr : strArr) {
      if(sArr.contains(_value)){
        System.out.println("sArr ---- > "+sArr);
        //myLocalList.add(sArr);
        return true ;
      }
    }
    return false;
  }).findFirst().get();

  return findFirst;
}

修改

使用可选检查:

        Optional<String> findFirst = myGlobalList.stream().filter(ele -> {
        ele = ele.replaceAll("\\[(.*?)\\]", "$1");

        String[] strArr = ele.split(",");
        for (String sArr : strArr) {
            if (sArr.contains(_value)) {
                System.out.println("sArr ---- > " + sArr);
                // myLocalList.add(sArr);
                return true;
            }
        }
        return false;
    }).findFirst();
    return findFirst.isPresent() ? findFirst.get() : null;

编辑2

findFirst抛出异常,因为原始列表已更改,请尝试使用collect将结果收集到新列表中,然后获取第一个值:

 return myGlobalList.stream().filter(ele -> {
        ele = ele.replaceAll("\\[(.*?)\\]", "$1");

        String[] strArr = ele.split(",");
        for (String sArr : strArr) {
            if (sArr.contains(_value)) {
                //System.out.println("sArr ---- > " + sArr);
                // myLocalList.add(sArr);
                return true;
            }
        }
        return false;
    }).collect(Collectors.toList()).get(0);