더북(TheBook)

코드는 괜찮아 보이지만 재고 목록 내 한 supply라도 오염되었을 경우 무조건 충돌합니다. 더 큰 문제는 이 문제가 처음 발생하기 전까지는 코드가 잘 동작한다는 점입니다. 더욱이 모든 제품이 깨끗하면 문제없이 동작할 테니 버그를 발견하기 어렵고요.

문제는 supplies를 순회하는 for 루프 내 supplies.remove(supply)를 호출하는 부분입니다. 이렇게 실행하면 List 인터페이스의 표준 구현이나 Set이나 Queue와 같은 Collection 인터페이스의 구현은 ConcurrentModificationException을 던집니다. List를 순회하며 List를 수정할 수 없습니다.

단일 스레드 애플리케이션에서 동시(concurrency) 실행이라니 ConcurrentModificationException이라는 이름이 꽤 이상하게 느껴집니다. 실제로 동시 실행은 일어나지 않으니 다소 오해의 소지가 있네요! 다름 아니라 Collection을 순회하는 동안 그 컬렉션을 수정한다는 뜻입니다. 불행히도 자바의 컴파일 타임 검사로는 이 오류를 잡아내지 못 합니다.

그렇다면 ConcurrentModificationException을 일으키지 않으면서 어떻게 올바르게 수행할까요?

class Inventory {

    private List<Supply> supplies = new ArrayList<>();
    void disposeContaminatedSupplies() { 
        Iterator<Supply> iterator = supplies.iterator();
        while (iterator.hasNext()) {
            if (iterator.next().isContaminated()) { 
                iterator.remove();
            } 
        }
    } 
}
신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.