728x90
앱 테스트 진행 중에 다음과 같은 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를 활용하여 대응했다.
구성 로직이나 스레드 처리 환경에 따라 선택적으로 활용할 필요가 있다.
728x90