동시성 프로그래밍

[자바 멀티쓰레드] 경쟁상태와 임계영역

Don't stop 훈 2023. 9. 7. 19:38
멀티 스레드 프로그래밍을 공부하기전에 멀티 쓰레드를 사용하는 이유는 무엇일까?
바로 여러개의 쓰레드를 사용하면 동시에 여러 가지 작업을 수행할 수 있어서, 애플리케이션의 반응성을 향상시킬 수 있기 때문이다. 또한 여러 작업을 동시에 실행하여 더 뛰어난 성능을 달성할 수 도 있다.
그러므로 멀티쓰레드 환경에서 프로그래밍을 할 때 중요한 부분들을 잘 알아둬야 한다.

 

스레드 안전성

스레드의 안전성을 알아보기전에 스레드의 가장 큰 특징을 알고가야한다.

바로 모든 스레드가 공유하는 메모리 공간을 가지고 있다는 것이다.

 

모든 스레드가 하나의 메모리 공간을 공유한다는 말은, 여러개의 스레드가 메모리에 동시에 접근하여 데이터를 조작할 수 있고,

데이터 경쟁상태와 같은 여러 문제들을 일으킬 수 있기 때문에 멀티쓰레드 환경에서 이러한 특징을 잘 이해하고 있어야 한다.

 

 

여러 스레드가 공유되는 메모리 공간에 동시에 접근할 수 없도록 하여 안전하게 하는 것을 스레드 안전성 이라고 한다.

즉, 공유 메모리에 있는 변경할 수 있는 객체(mutable)에 값을 동시에 변경하지 못하도록 막는다는 의미이기도 하다.

 

스레드 안전성을 정확성으로도 정의할 수 있는데, 여러 스레드가 클래스에 접근할 때 어떠한 동작을 수행해도 정확하게 동작하면 해당 클래스는 스레드 안전하다고 말한다.


경쟁상태(race condition)와 임계영역(critical section)

경쟁상태는 여러 종류의 경쟁 조건이 발생할 수 있기 때문에 결과를 신뢰할 수 없는 상태이다.

멀티쓰레드 환경에서 경쟁상태가 발생할 수 있는 영역을 임계역역이라고 한다.

 

경쟁상태가 발생할 수 있는 대표적인 아래의 2개 예시가 있다.

 

1. 단일 연산

count++와 같이 원자적 연산이 아닌 경우 발생할 수 있다. ++ 연산의 경우 기계어로 컴파일할 때 단일연산이 아닌 3개의 연산으로 이루어져 있기 때문에 여러 스레드 접근 시 원하지 않는 결과가 나올 수 있다.

public void add() {
    count ++;
}


아래 그림처럼 여러 스레드에서 동시에 count++을 할 때, count의 기대값은 7 이지만 실제로는 6으로 바뀌어 버릴 수 있다.(치명적!)

여러 스레드가 동시에 쓰기 연산중..

 

 

2. 늦은 초기화 시 경쟁조건

아래처럼 Instance가 null인걸 확인한 시점과 instance에 객체를 할당하는 시점 사이에 다른 스레드가 intance 의 값을 바꿔버린다면 문제가 생길 수 있다. 즉 판단 시점과 변경 시점 사이에 다른 스레드가 끼어들 수 있다는 것이다.

public Object getInstance() {
    if (instance == null) {
        instance = new Object();
    }
    return instance;
}

 

 

 

<참고자료>

자바 병렬 프로그래밍 - https://product.kyobobook.co.kr/detail/S000000935083

운영체제 - https://product.kyobobook.co.kr/detail/S000001868743