Search code examples
javajava-8java-streamconcurrentmodification

java8 stream map reduce cause a the ConcurrentModificationException, why?


final BigDecimal couponlessAmount = orderItems.stream()
            .filter(item -> !item.getIsUseCoupon())
            .map(item -> item.getTotalAmount().subtract(item.getReduceProductAmount()))
            .reduce(BigDecimal.ZERO, BigDecimal::add);

something causes the java.util.ConcurrentModificationException

java.util.ConcurrentModificationException
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1380) ~[?:1.8.0_77]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) ~[?:1.8.0_77]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) ~[?:1.8.0_77]
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[?:1.8.0_77]
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_77]
    at java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:474) ~[?:1.8.0_77]
    at com.yijiupi.himalaya.ordercompute.provider.domain.component.computer.CouponUseLimitComputer.getMaxUseAmount(CouponUseLimitComputer.java:103) ~[classes/:?]

Solution

  • It's unlikely to be JDK/JIT bug. As usually with ConcurrentModificationException it's a sign that your orderItems is concurrently modified from another thread. You should not use ArrayList concurrently without providing proper external synchronization. Note that wrapping ArrayList into Collections.synchronizedList is not enough here as it does not synchronizes traversals. As an alternative (if modifications are rare) use CopyOnWriteArrayList.