Development/Android

[Android] Fatal Exception: java.util.ConcurrentModificationException 동시성 문제 해결

SeungYong.Lee 2024. 1. 6. 20:48
반응형

앱 테스트 진행 중에 다음과 같은 Exception이 발생했다.

Fatal Exception: java.util.ConcurrentModificationException

 

여러 스레드에서 하나의 컬렉션에 접근할 때, 동시성 문제가 발생하는 것으로 확인된다.
문제가 발생한 코드로 이동해 보니...

object DataManager {

    private var dataInfos = ArrayList<DataInfo>()
    
    .....

object Manager 내부의 dataInfos라는 리스트가 있고, 해당 DataManager가 외부에서 여러 스레드에 동시 호출되며 dataInfos에 접근하던 중 문제가 발생하는 것으로 확인했다. 싱글톤 하위 리스트를 여러 스레드 접근에 안전하도록 처리할 필요가 있었다.

 

object DataManager {
    private var dataInfos = Collections.synchronizedList(ArrayList<DataInfo>())

    @Synchronized
    fun modifyDataInfos(newDataInfo: DataInfo) {
        // 동기화된 블록 내에서 컬렉션 수정
        dataInfos.add(newDataInfo)
    }
}

1. 리스트 자체에 Lock이 걸리는 synchronizedList 활용. 리스트가 사용되는 함수에 @Synchronized 어노테이션을 적용해주어야 한다.

쓰기 접근이 많은 경우 사용하는 것이 더 적합하다.

 

object DataManager {
    private var dataInfos = CopyOnWriteArrayList<DataInfo>()

    fun modifyDataInfos(newDataInfo: DataInfo) {
        // 동기화된 블록 내에서 컬렉션 수정
        dataInfos.add(newDataInfo)
    }
}

2. 읽기, 쓰기 과정에서 Lock과 함께 리스트를 복사 후 쓰기 작업을 진행하는 CopyOnWriteArrayList를 활용.

읽기 접근이 많은 경우 사용하는 것이 더 적합하다.

 

필자는 읽기 접근 쓰기 접근보다 상대적으로 많은 로직을 사용 중이기에, CopyOnWriteArrayList를 활용하여 대응했다.
구성 로직이나 스레드 처리 환경에 따라 선택적으로 활용할 필요가 있다.

반응형