-
멀티스레딩 환경에서 발생할 수 있는 경쟁상태 해결의 경우 왜 많은 라이브러리들이 Synchronized 를 사용해 임계구역을 설정함으로써 해결하고 있나요?IT/cs 2025. 2. 15. 16:37SMALL
멀티스레딩 환경에서 발생할 수 있는 문제 중에는 대표적으로 경쟁상태가 있습니다.
경재상태란 하나의 공유자원에 여러 스레드가 접근하여 값을 변경하는 경우에 해당 공유자원에 대한 기대했던 값과는 다른 값의 불일치 문제가 발생할 수 있는 상태를 의미합니다.
경쟁상태를 해결하는 여러 방법이 있는데요, 대표적으로
1. Synchronized 를 사용한 임계구역 설정2. Atomic 연산을 지원하는 클래스를 활용
3. Mutex or Semaphore 을 이용한 스레드 Lock 관리
가 있습니다.
먼저 의문이 들었던것은 Synchronized 보다 Atomic 연산을 제공하는 클래스를 활용하는것이 더 간단하고 가독성도 좋을것 같은데 왜 사용하지 않는걸까? 였습니다.
그 이유는 바로 Atomic 연산을 제공하는 클래스는 단 하나의 변수에 대한 CAS(Compare and Swap) 연산을 실행하기 때문입니다. 단순히 해당 변수 하나에대한 스레드의 경쟁상태를 방지하는 것이라면 Atomic 연산으로 처리할 수 있지만, 만약 하나의 변수에대한 연산이 아닌 여러 작업들을 하나의 트랜잭션 단위처럼 처리해야 하는 경우에는 경쟁상태를 해결할 수 없게됩니다.
* CAS (Compare and Swap) 연산이란?
하드웨어 수준에서 현재 변수의 값과 내가 기대하고있는 현재 변수의 값 을 비교하고 일치하는 경우에만 값은 변경해주는 연산입니다. 하드웨어수준에서 원자적 연산을 보장하기때문에 멀티스레드 환경에서도 안전합니다.
ex)
var value = AtomicInteger(0) <- 현재값
var expectedValue = 0
var newValue = 1
value.comareAndSet(expectedValue, newValue)
// 여기서 expectedValue 는 내가 기대하고있는 현재 value 의 값,
// 해당 값와 현재 value 가 일치한다면 newValue 로 값을 변경, 그렇지 않다면 변경하지 않고 실패후 재시도두번째로는 Mutex 나 Semaphore 을 활용하여 lock 을 설정하여 스레드의 접근을 방지하는 방법을 사용하지 않는걸까? 라는 의문이었습니다. 왜냐하면 Synchronized 의 경우 오버헤드가 많아 성능적으로 문제가 있다고 알고 있었기 때문입니다.
Synchronized 의 경우 jvm 의 최적화의 발달로 인하여 오버헤드를 많이 줄였다고 평가되고 있습니다. 그리고 Mutex 또는 Semaphore 의 경우 단순한 임계구역 설정 뿐 아니라 조건별, 특히 Semaphore 의 경우 접근할 수 있는 스레드의 개수를 제한할 경우 사용되는것이 더 목적에 맞다고 볼 수 있습니다. 이에따라 Synchrnized 로 임계구역을 설정하는것이 성능상, 그리고 가독성 측면에서도 나쁘지 않아서 사용됩니다.
LIST