SeouliteLab

[Java/자바] ConcurrentModificationException 발생 및 해결 방법 본문

프로그래밍

[Java/자바] ConcurrentModificationException 발생 및 해결 방법

Seoulite Lab 2024. 3. 9. 00:56

ConcurrentModificationException이란?

Java에서는 여러 스레드가 동시에 컬렉션을 수정할 때 ConcurrentModificationException이 발생할 수 있습니다. 이는 컬렉션을 반복하는 도중에 해당 컬렉션의 구조가 변경되었을 때 발생합니다. 이 문제를 해결하기 위해서는 몇 가지 방법이 있습니다.

ConcurrentModificationException 발생 원인

ConcurrentModificationException은 일반적으로 다음과 같은 상황에서 발생합니다.

  • 반복자(iterator)를 사용하여 컬렉션을 순회하는 중에 컬렉션을 수정할 경우
  • 여러 스레드가 동시에 컬렉션을 수정할 경우

ConcurrentModificationException 해결 방법

ConcurrentModificationException을 해결하는 방법은 다양하지만, 주로 다음과 같은 방법을 사용합니다.

  1. Enhanced For Loop 사용 시 ConcurrentModificationException 방지
  2. Iterator 사용 시 ConcurrentModificationException 방지
  3. Synchronized 또는 Concurrent 컬렉션 사용

Enhanced For Loop 사용 시 ConcurrentModificationException 방지

Enhanced For Loop를 사용하여 컬렉션을 반복하는 경우, 컬렉션을 직접 수정하지 않는 것이 좋습니다. 대신 반복 중에 수정이 필요한 경우 임시 컬렉션을 만들어 수정을 수행하는 것이 좋습니다.


List list = new ArrayList<>();
list.add("one");
list.add("two");

// 잘못된 예제
for (String s : list) {
    if (s.equals("two")) {
        list.remove(s); // ConcurrentModificationException 발생
    }
}

// 올바른 예제
List tempList = new ArrayList<>();
for (String s : list) {
    if (!s.equals("two")) {
        tempList.add(s);
    }
}
list = tempList;

Iterator 사용 시 ConcurrentModificationException 방지

Iterator를 사용하여 컬렉션을 순회하는 경우에도 동일한 원칙이 적용됩니다. 반복 중에 컬렉션을 직접 수정하는 것은 피해야 합니다.


List list = new ArrayList<>();
list.add("one");
list.add("two");

Iterator iterator = list.iterator();
while (iterator.hasNext()) {
    String s = iterator.next();
    if (s.equals("two")) {
        iterator.remove(); // ConcurrentModificationException 방지
    }
}

Synchronized 또는 Concurrent 컬렉션 사용

스레드 안전한 Synchronized 컬렉션이나 Concurrent 컬렉션을 사용하는 것도 ConcurrentModificationException을 방지하는 좋은 방법입니다.


Map synchronizedMap = Collections.synchronizedMap(new HashMap<>());

ConcurrentModificationException 해결 예제

아래는 ConcurrentModificationException을 해결하는 다양한 방법을 보여주는 예제 코드입니다.


import java.util.*;

public class ConcurrentModificationExample {
    public static void main(String[] args) {
        // 예제 1: Enhanced For Loop를 사용하여 컬렉션 순회
        List list = new ArrayList<>(Arrays.asList("one", "two", "three"));
        List tempList = new ArrayList<>();
        for (String s : list) {
            if (!s.equals("two")) {
                tempList.add(s);
            }
        }
        list = tempList;
        System.out.println("After removing 'two' using Enhanced For Loop: " + list);

        // 예제 2: Iterator를 사용하여 컬렉션 순회
        List list2 = new ArrayList<>(Arrays.asList("one", "two", "three"));
        Iterator iterator = list2.iterator();
        while (

iterator.hasNext()) {
            String s = iterator.next();
            if (s.equals("two")) {
                iterator.remove();
            }
        }
        System.out.println("After removing 'two' using Iterator: " + list2);

        // 예제 3: Synchronized 컬렉션 사용
        Map synchronizedMap = Collections.synchronizedMap(new HashMap<>());
        synchronizedMap.put("key1", "value1");
        synchronizedMap.put("key2", "value2");
        System.out.println("Synchronized Map: " + synchronizedMap);
    }
}