스레드 안전 Intro

여러 Thread에서 객체에 접근할때, 객체가 항상 정확한 상태를 유지해야 스레드안전이 보장됩니다. 동기화는 하나의 Thread에 의해 변경되는 도중에 다른 스레드의 접근이 가능한 모든 변수를 읽거나 쓰는 코드에 적용되어야 합니다. 이러한 코드 영역을 임계여역이라고 하며, 임계영역은 원자적으로 실행되어야합니다. 결론적으로 말하자면, 한번에 하나의 스레드만 접근을 허용하도록 실행되어야 합니다.



암시적 잠금과 JAVA Monitor

 synchronized 키워드는 모든 자바 객체에서 사용하는 암시적 잠금으로 동작하게 됩니다.  임계영역에서 스레드의 실행이 한스레드에 독점적임을 의미하게됩니다. 

 하나의 스레드가 임계영역을 점유하는 동안 다른 스레드의 접근은 차단되고, 잠금이 해제될때까지 실행할수 없게됩니다. 


Java monitor에는 3가지 상태가 있습니다.


차단된 스레드, 실행중인 스레드, 대기스레드가 있습니다.


JAVA Monitor 3가지 모델링


1. 차단된 스레드

다른스레드에 의해 해제될 모니터를 기다리는 동안, 일시 중단된 스레드입니다.


2. 실행 중 스레드

모니터를 소유하고 현재 임계영역에서 코드를 실행중인 스레드입니다.


3. 대기 스레드

임계영역의 끝에 도달하기 전에 자발적으로 모니터의 소유권을 포기한 스레드입니다. 이 스레드는 사기 소유권을 얻을 때까지 스레드의 신호를 기다립니다.


스레드에 접근(1) -> 차단된스레드(2) -> 실행중인스레드(3) -> 대기스레드(4)   -> 다시 실행중인 스레드(5), (상황에 따라서)

위의 그림에있는 상태설명.


1. 모니터에 진입

스레드가 암시적 잠금에 의해 보호된 영역에 접근을 시도합니다. 이 스레드는 모니터에 들어가게됩니다. 만약 다른 스레드가, 이미 잠금을 차지하고 있으면 스레드의 잠금 획득이 연기되게 됩니다.


2. 잠금 획득

모니터를 소유하고 있는 다른 스레드가 없는경우, 차단된 스레드는 소유권을 획득하고 임계영역에서 실행되게 됩니다. 


3. 잠금 해제 및 대기

스레드는, 계속 실행하기 전에 충족해야할 조건을 기다려야 하는 경우도있습니다. (생산자 소비자문제처럼, 다른 스레들간의 순서를 조율하거나, 조건등에따라 스레드 실행순서를 제어하고자할때).

그럴때는 Object.wait()를 통해서 스레드 자신의 실행을 일시 중단합니다.


Object.wait()을 하게되면 Object (주로, synchronized에 쓰이는 열쇠? 동기화 구분의 변수명가 되겠습니다.) 를 synchronized하며, 실행중인 스레드영역에있던 스레드는, 열쇠를 내어놓고, 대기 스레드에 들어가서 notify가 다른 스레드에서 호출되기전까지 대기하게 됩니다. 

다른 실행중인 스레드에서 notify가 호출되면 대기스레드에있던 스레드는 다시 열쇠를획득하고 실행중인 스레드(4.과정)으로 들어가게됩니다.



4. 신호 후 잠금 획득

대기 스레드가 Object.notify(), Object.notifyAll()을 통해, 다른스레드로부터(실행중이었던 스레드) 신호를 받고, 스케줄러에 의해 선택되면, 다시 모니터의 소유권을 가지게됩니다. 하지만, 대기스레드가, 모니터를 소유할 가능성은, 잠재적으로 차단된 스레드보다는 앞설수 없다고합니다.



5. 잠금 해제 및 모니터 종료

임계영역의 끝에서 스레드는 모니터를 종료하고, 다른 스레드가 모니터를 소유할 수 있도록 자리를 떠나게 됩니다.



위의 다섯가지 순서는 아래의 코드와도 같습니다.

synchronized(this) { //(1) 

   // 코드 실행 (2)

   wait(); (3)

   // 코드 실행 (4)

}(5)




다음 포스팅에서는, 암시적 잠금사용의 예제와 소비자와 생산자 코드를 살펴보도록 하겠습니다.


다음 포스팅으로 가기 <= 클릭





+ Recent posts