[Java] 자바 8 Streams와 ConcurrentModificationException

2022. 1. 3. 18:19개발/Java, Spring

dataMap.forEach((k, v) -> {
	func(v);
	dataMap.remove(k);
});

Spring Application을 만드는데 동시성 보장이 필요해 ConcurrentHashMap을 사용하였는데, Streams를 사용한 다음 로직에서 ConcurrentModificationException이 발생했다.

 

발생 원인을 확인해보니 Collection.forEach(Stream도 collection)의 로직 동안은 데이터가 immutable 해야한다. 따라서 수정을 감지한 즉시 ConcurrentModificationException을 던지며 프로그램을 멈춘다. 즉 ConcurrentHashMap과 상관없이, forEach와 연관되어있는 문제였다.

 

for(Map.Entry<String, List<String>> e : dataMap.entrySet()) {
	List<String> documents = dataMap.remove(e.getKey());
	func(documents);
}

다음과 같이 고전적인 foreach문을 사용하기로 하였다.

remove가 Thread-safe하고 삭제된 value값을 리턴해주기에 저런 트릭이 많이 사용 된다고한다.

 

Java 8 의 stream은 가독성적인 측면에는 좋은듯 하나 활용할때 이러한 경우를 잘 고려해봐야할듯하다.