Android
[Android] 경쟁 상태(Race Condition)란?
참깨빵위에참깨빵_
2024. 9. 29. 22:11
728x90
반응형
아래는 경쟁 상태를 설명하는 영문 위키백과다.
https://en.wikipedia.org/wiki/Race_condition
경쟁 조건은 시스템의 실질적인 동작이 제어할 수 없는 다른 이벤트의 순서, 타이밍에 의존해서 예기치 않거나 일관되지 않은 결과를 초래하는 시스템 상태를 말한다. 가능한 동작 중 하나 이상이 바람직하지 않은 경우 버그가 된다...(중략)...특히 논리 회로나 멀티 쓰레드, 분산 소프트웨어 프로그램에서 경쟁 조건이 발생할 수 있다. 상호 배제를 사용하면 분산 소프트웨어 시스템에서 경쟁 조건을 막을 수 있다...(중략)...동시 실행되는 코드 경로가 여러 개 있을 때 소프트웨어에서 경합 조건이 발생할 수 있다. 여러 코드 경로가 예상과 다른 시간이 걸리면 예상과 다른 순서로 완료되서 예기치 않은 동작으로 인해 버그가 발생할 수 있다. 심각한 경합 조건은 잘못된 실행, 소프트웨어 버그를 유발한다. 치명적 경쟁 조건은 프로세스나 쓰레드가 일부 공유상태에 의존할 때 발생한다. 공유 상태에 대한 작업은 상호배타적이어야 하는 중요한 섹션에서 수행된다...(중략)...경함 조건은 최종 결과가 비결정적이고 간섭하는 쓰레드 간의 상대적 타이밍에 따라 달라지기 때문에 재현, 디버깅이 어려울 수 있다. 따라서 이런 성격의 문제는 디버그 모드로 실행하거나 로그 추가, 디버거를 연결하면 사라질 수 있다. 디버깅 중에 이렇게 사라지는 버그를 하이젠버그라고 한다. 따라서 신중한 소프트웨어 설계를 통해 경쟁 조건을 피하는 게 좋다
경쟁 조건은 안드로이드에서도 발생할 수 있는 문제다. 어떤 메모리 위치를 대상으로 둘 이상의 읽기 or 쓰기 작업이 거의 동시 실행되어 어떤 작업이 먼저 완료될지 예측할 수 없는 경우에 발생할 수 있다. 안드로이드에선 아래 경우에 발생할 수 있다.
- 비동기 작업 : 쓰레드, 코루틴 등을 쓸 때 여러 쓰레드가 공유 리소스에 접근할 때
- UI 업데이트 : 백그라운드 쓰레드에서 UI를 직접 업데이트하려고 할 때
- 싱글톤 패턴 : 멀티 쓰레드 환경에서 싱글톤 인스턴스를 만들 때 적절한 동기화가 없는 경우
- 쉐어드 프리퍼런스 : 여러 쓰레드에서 동시에 읽기 / 쓰기 작업을 수행할 때
- DB : 동시에 여러 DB 트랜잭션이 실행될 때
- 네트워크 요청 : 여러 쓰레드에서 동시에 네트워크 요청을 처리할 때
- 서비스 시작 / 중지 : 서비스의 생명주기 함수가 동시 호출될 때
- 브로드캐스트 리시버 : 여러 리시버가 동시에 같은 리소스에 접근할 때
텍스트뷰가 있고 두 쓰레드에서 이 텍스트뷰에 각각 1, 2라는 숫자를 표시하라고 동시에 명령을 내린다면 텍스트뷰는 결국 어떤 숫자를 표시해야 하는가?
이런 경우가 발생하지 않게 조심해야 한다. 안드로이드에서 경쟁 조건이 발생하지 않게 하려면 아래 방법들을 고려해볼 수 있다.
방법 | 설명 |
동기화 매커니즘 사용 | synchronized를 메서드나 코드 블록에 써서 한 번에 하나의 쓰레드만 접근할 수 있게 하거나, Lock 인터페이스를 써서 동기화를 세밀하게 제어한다 |
thread-safe한 자료구조 활용 | ConcurrentHashMap 등 동시성을 지원하는 컬렉션을 사용하거나, AtomicBoolean 등 atomic 타입을 써서 원자적 연산을 수행한다 |
핸들러 사용 | 메인 쓰레드(UI 쓰레드)와 백그라운드 쓰레드 간 통신을 안전하게 처리한다 |
쓰레드 풀 사용 | ExecutorService를 써서 동시성을 제어한다 |
불변 객체 사용 | 원천적으로 동시성 문제를 방지할 수 있는 방법이다 |
volatile 키워드 사용 | 변수의 가시성을 보장해서 멀티 쓰레드 환경에서의 일관성을 유지한다 |
SingleThreadExecutor 사용 | 순차적 실행이 필요한 작업에 사용한다 |
코루틴 활용 | 비동기 프로그래밍을 단순화하고 동시성 관리를 개선한다 |
ConcurrentHashMap은 코틀린 공식문서에만 있을 줄 알았는데 의외로 안드로이드 디벨로퍼에도 공식문서가 존재한다.
https://developer.android.com/reference/kotlin/java/util/concurrent/ConcurrentHashMap
Atomic이 붙은 타입은 멀티 쓰레드 환경의 중요 개념인 동시성, 가시성, 원자성 중 원자성을 보장하기 위해 설계된 타입이다. 하나의 변수에 원자적 연산이 필요하거나 원자적 접근을 보장할 때 사용할 수 있다.
원자적 연산은 읽기, 쓰기, 갱신 등 작업이 중단 없이 완전하게 실행되는 걸 말한다. 원자성을 더 알아보는 건 이 포스팅의 범위를 넘기 때문에 생략한다.
반응형