synchronized 키워드는 특정 메서드나 코드 블록을 한번에 한 스레드만 사용하도록 보장한다. 동기화는 스레드가 일관성이 깨진 객체를 관측할 수 없도록 할 뿐 아니라(하나의 스레드만 이용), 동기화 메서드나 동기화 블록에 진입한 스레드가 동일한 락의 보호 아래 이루어진 모든 변경의 영향을 관측할 수 있도록 보장한다(기존의 스레드가 변경한 내용을 새로운 스레드가 관측 가능). 


 성능을 높이기 위해서는 원자적 데이터를 읽거나 쓸 때 동기화를 피해야 한다는 이야기를 자주 들어봤을 것이다. 상호 배제성뿐 아니라 스레드 간의 안정적 통신을 위해서도 동기화는 반드시 필요하다. 즉 하나의 스레드만 이용할 수 있도록 하는 것의 용도 뿐만아니라 스레드 간의 안정적 통신을 위해서는 동기화를 사용해야 한다는 뜻이다. 자바의 메모리 모델 명세 때문이다. 메모리 모델은 한 스레드가 만든 변화를 다른 스레드가 볼 수 있게 되는 시점과, 그 절차를 규정하기 때문이다. 즉 기존의 스레드가 변경한 내용을 새로운 스레드가 알도록 하는 것을 규정한다는 것.


위의 클래스는 Thread.stop 대신 boolean 필드를 이용하여 스레드를 제어 했다. stop메서드는 안전성이 결여되어있으므로 사용하면 안된다. 위의 프로그램은 1초가 지나면 main 스레드가 stopRequested의 값을 true로 바꾸므로, 후면 스레드가 실행하는 순환문도 그 때 종료될 것 같다. 하지만 그렇지 않다.

이 프로그램의 문제는 동기화 메커니즘을 적용하지 않은 탓에 main스레드가 변경한 stopRequest의 새로운 값을 후면 스레드가 언제쯤 보게 될지 알 수가 없다는 것이다. 위의 프로그램은 아래와 같이 변경되어야 한다.


 하지만 StopThread의 동기화 메서드가 하는일은 동기화 없이도 원자적이다. 다시 말해서, 이들 메서드에 동기화를 적용한 것은 상호배제성을 달성하기 위해서가 아니라, 순전히 스레드 간 통신 문제를 해결하기 위해서 였다는 것이다. 동기화를 실행하는 비용이 크기 때문에 좀더 개선하기 위해서는 stopRequested를 volatile로 선언하면 최적화에서 제외되므로 좀 더 나은 성능을 얻을 수 있다. 

요약

변경 가능한 데이터를 공유하지 않는 것이 가장 좋다. 그러나 공유해야만 하는 경우에는 해당 데이터를 읽거나 쓰는 모든 스레드는 동기화를 수행해야 한다는 것이다. 동기화를 하지 않으면 다른 스레드가 만든 변경사항을 관측할 수 있으리라는 보장을 할 수 가 없다.  변경 가능 데이터를 적절히 동기화하지 않으면 생존 오류나 안전 오류(2개 이상의 스레드에 안전하지 않음. 변경도중 다른스레드가 접근)가 생긴다. 



+ Recent posts