본문 바로가기

소프트웨어/Android/Java/Ndk

JavaEffective] 변경 가능 데이터의 동기화(Lock, Synchronized, Volatile)

참고자료. 인사이트 출판 JavaEffective 2/E. Joshua Bloch


------------------------------------------

%참고, 퇴근후 책읽고 10분동안 작성하는거라(출근을 위해 자야함..) 나와있는 코드는 안맞을수도 있음. 개념적인것만 이해하면 될 듯.


개발하면서 보통 동기화를 잘 안시키는 편이었다. 대부분의 프로그램이 단일 Thread(Main제외) 상황이었기 때문에 딱히 필요성을 못느꼈기 때문이다. 다만, Loop문이 돌고있는 Thread에서는, 프로그램 종료시나 임의로 종료를 원할때 Loop를 탈출하는 방법이 필요했다. 

- 주저리. 처음 Thread란걸 만져봤을땐 도대체 이걸 어떻게 멈추나..하는 고민을 했었다. Thread.stop, Thread.pause등등. 삽질을 많이했었다.



Loop문이 돌고있는 Thread라면 아래와 같은 예를 들 수 있겠다.


new Thread(new Runnable() {
 public void run() {
   while(1) {
      Log.d("mstag","i'm runnnnnn");
   }
 }
}).start();

이런 구조에서 탈출을 시키려면? (혹은 한 작업이 끝나기 전에 특정 변수에 접근하지 못하게 하려면?)

public static boolean stop = false;
new Thread(new Runnable() {
 public void run() {
   while(!stop) {
      Log.d("mstag","i'm runnnnnn");
   }
 }
}).start();



이렇게 작성하면 된다.

(락을 걸고싶다면 단순하게 변수 놔두고 spin lock을 걸던지 조건을 바꾸던지 하면 될 것이다.방법은 많으니 생각해볼 것!)

(api찾아보니 AotmicBoolean Class가 조금 더 안전할 듯 함)




그런데 위의 코드는 정확한 동작이 보장되는 코드는 아니다. 

프로그래머가 thread를 멈추기 위해 코드 어디에선가 stop변수에 true를 집어넣어도 해당 thread에서는 언제 변경된 stop변수값을 읽을지 알 수 없다.


그래서 동기화를 위해 synchronized R/W method를 만들면 된다.

private static synchronized void setStopTrue() { // Write
stop = true;
}
private static synchronized boolean getStop() { // Read
return stop;
}

new Thread(new Runnable() {
 public void run() {
   while(!getStop()) {
      Log.d("mstag","i'm runnnnnn");
   }
 }
}).start();

//어디선가 스레드를 멈추게 하고 싶은 부분에서
//..
//..
setStopTrue();


읽기/쓰기 매서드에 모두 적용하였기때문에 동기화가 되었다. 책으로 보다보니 뒤에 volatile관련해서도 나오던데, 이 부분은 궁금하면 다시 찾아볼 것.

간단하게 정리하면 

volatile은 Mutex는 없지만, 어느 Thread건 Read에서 가장 최근값을 보장하기때문에 syncrhonized method없이도 동기화와 비슷한 긴으을 하게함. 즉, volatile로 선언된 변수는 atomic field의 변수가 되는 것. (그런데 책에서는 다루기 까다롭다고 소개하기도 하고, 평소에 내가 잘 안쓰는 방식이기도 해서 이정도로만..)




정리.

1. 변경 가능한 데이터는 공유 X

2. 변경 가능 데이터는 되도록 한 thread에서만..

3. 이것도 저것도 복잡하면 그냥 boolean 변수로 lock걸어버려도 됨(원자성 보장 안됨)

4. Synchronized Method로 R/W Method를 만들어 사용하면 원자성 보장됨