brunch

You can make anything
by writing

C.S.Lewis

by 이승현 Sep 11. 2018

동시성(Concurrency)

#66 공유하는 가변 데이터에 접근 시 동기화 하자

Effective Java - 동시성(Concurrency)


#01 https://ko.wikipedia.org/wiki/%EC%8A%A4%EB%A0%88%EB%93%9C_(%EC%BB%B4%ED%93%A8%ED%8C%85)


스레드(thread)를 통해 여러 작업을 동시에 처리할 수 있는데, 이러한 프로그래밍을 동시 프로그래밍(concurrent programming)이라 합니다.


당연히 단일 스레드 프로그래밍보다 어렵고 복잡한데, 이를 잘 처리할 수 있는 방법들에 대해 알아보겠습니다.


#66 공유하는 가변 데이터에 접근 시 동기화하자


#02 Synchronization


synchronized 키워드를 이용하면 한 번에 하나의 스레드만 메서드나 블록에 접근할 수 있습니다.

이를 상호 배제(mutual exclusion)를 위한 동기화라고 합니다.


동기화는 상보 배제뿐만 아니라 스레드 간 신뢰성 있는 변수 값 전달에도 필요합니다.


아래 코드는 서로 다른 스레드 간 중단(stop) 동작을 동기화 없이 구현한 코드입니다.

현재 Thread.stop() 메서드는 deprecated 된 상태입니다.
#03 StopThread class


초기값이 false인 stopRequest boolean 필드를 두 스레드가 공유하고 있습니다.

backgroundThread는 mainThread가 1초 뒤에 stopRequest 필드 값을 true로 바꾸면, 동작을 중단하게 되어 있습니다.


#04 Non synchronized


하지만 실제로는 1초 뒤에 동작을 중단하지 않고, 무한대로 실행되고 있습니다.

동기화가 안되어 있기 때문에 가상 머신이 내부적으로 최적화(hoisting)를 통해 코드를 변경을 해서 이러한 결과가 나오고 있습니다. (VM에 따라 동작이 다를 수 있습니다.)

while(!done) { // origin code
    i++;
}
if (!done) { // hoisting
    while(true) {
        i++;
    }
}




아래 코드는 서로 다른 스레드 간 중단(stop) 동작을 동기화를 통해 구현한 코드입니다.

#05 SynchronizedStopThread class


초기값이 false인 stopRequest boolean 필드 값을 변경하는 requestStop 메서드와, 이를 읽는 stopRequest() 메서드 둘 다 동기화되어 있습니다.


#06 synchronized


필드를 읽는 동작과 변경하는 동작 모두 동기화를 통해 상호 배재뿐만 아니라, 변수 값을 확실하게 전달할 수 도 있습니다.




volatile을 통해 구현할 수 도 있습니다.

#07 VolatileStopThread class


stopRequested 필드를 volatile로 선언하면 동기화를 통해 상호 배제를 수행하진 않지만, 이 필드 값을 읽는 스레드에서는 가장 최근에 변경된 값을 얻을 수 있습니다.

동기화에 비해 기능은 단순하지만, 그만큼 비용이 줄어들기 때문에 상황에 따라 이용할 수 있습니다.




이런 상황들을 애초에 만들지 않기 위해서는, 가변 데이터를 공유하지 않도록 해야 합니다.

즉, 가변 데이터는 단일 스레드에서만 이용하는 게 좋습니다.

하지만 프로그래밍을 하다 보면 필연적으로 발생할 수 있기 때문에, 가변 데이터에 접근 시 동기화를 해야 합니다.

만약 스레드 간 상호 배제 없이, 확실한 값만 전달이 필요하다면 volatile을 이용하는 게 좋습니다.


매거진의 이전글 예외(Exceptions)
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari