codemaster001
codemaster001

Reputation: 313

Java8 stream: ConcurrentModificationException while converting a list to another list

I have an executer service with a thread pool of 3 and each thread is accessing a synchronizedList and converting it to a list of Map

List<String> fruitList = Collections.synchronizedList(new ArrayList<>());
fruitList.add("banana");
fruitList.add("banana");
fruitList.add("banana");
fruitList.add("banana");
fruitList.add("kiwi");
fruitList.add("mango");
fruitList.add("mango");
fruitList.add("papaya");

I want to convert this list to a list of map where fruitName will be key and frequency of item will be the value

[{"banana" : 4}, {"mango" : 2}, {"kiwi" : 1}, {"papaya" :1}]

I tried something like this

Map<String, Long> fruitMap = fruitList.stream().collect(Collectors.
                        groupingBy(e -> e, Collectors.counting()));

But, occasionally I am getting the following error. How can I resolve this?

[java] Exception in thread "pool-3-thread-3" java.util.ConcurrentModificationException
     [java]     at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1388)
     [java]     at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
     [java]     at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
     [java]     at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
     [java]     at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
     [java]     at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:566)

Upvotes: 0

Views: 537

Answers (1)

Kartal Tabak
Kartal Tabak

Reputation: 894

If fruitList is updated in the middle of .stream().collect() process, you shall get that exception. A proper critical section definition and synchronization should be created to avoid that.

Although Collections.synchronizedList() does synchronization for most of the methods, it does not synchronize Collection.stream() and other methods on the stream. You need to synchronize your stream process manually.

That should work:

synchronized(fruitList) {
    Map<String, Long> fruitMap = fruitList.stream()
                       .collect(Collectors.groupingBy(e -> e, Collectors.counting()));
}

Upvotes: 1

Related Questions