java volatile : 변수의 가시성과 최적화

OS/이론 2020. 12. 16. 06:30

 면접 질문들을 모아놓은 레포를 보다 보면, 싱글톤 패턴은 많이 언급한다는 것을 알 수 있습니다. 거기서 DCL 패턴이 나오고, volatile도 나오는데요. 여기서 volatile이 무엇을 의미할까요?

 


 먼저, 간단하게 프로그램을 작성해 보겠습니다. Main 스레드와 Worker1 스레드 하나가 있습니다. 이 프로그램은, Main Thread에서 w1의 stop flag를 중간에 true로 셋팅합니다.

 

 

 Worker1의 run 메소드는 그냥 stop flag가 false이면 계속 돕니다. 결과가 어떻게 나올까요?

 

 

 공교롭게도, 0 : stop flag만 출력하고 더 이상 진행되지 않습니다. 이는 왜 그럴까요? 공식 문서를 보면 자세히 알 수 있습니다.

 


 Note 바로 윗 단락의 내용을 천천히 봅시다. 일단, while loop가 도는 동안에 stop flag는 자주 접근이 되는 대상이였습니다. 그렇기에, 컴파일러는 register에 stop flag를 넣을 수 있습니다. 이 상황을 그림으로 그려 봅시다.

 

 

 레지스터에 stop을 올렸다. 그런데, 그 다음에 이런 문장이 나옵니다. 매번 테스트를 할 때 마다 메모리에 있는 변수에 접근하지 않는다. 이건 또 무슨 말일까요? memory hierarchy나 register speed라는 키워드로 검색을 해 보시면 많이 보이는 그림은, register가 맨 위에 있고, 다음에 cache, main memory가 있는 그림입니다. 이 포스팅을 설명하는 데 필요한 부분만 그리면 아래와 같습니다.

 

 

 대략적으로 그려보면 위와 같습니다. Worker 스레드에 대해서, stop은 false였고, 컴파일러 최적화가 되었다면, 레지스터에 있는 stop도 false가 올라가 있을 겁니다. 그런데, 왜 메인 메모리에 접근하지 않을까요? 레지스터에 올려져 있기 때문입니다. 그리고 거기서 읽어들이는 게 효율적이기 때문입니다.

 

 문제는, main에서 w1.stop을 바꾸었을 때입니다.

 

 

 이 때에는 register에 올라간 stop 말고 다른 stop이 바뀌게 될 수도 있습니다. 예를 들자면 메인 메모리에 올라간 stop이라던지. 예를 들어서, 1번 코어가 worker1 thread를 수행하고, 2번 코어가 main thread를 수행한다고 해 봅시다. 그런데, 이미 worker1 스레드에 있는 stop을 읽어올 때, 레지스터에 있는 stop을 읽어올 거에요.

 

 

  그런데, 사실 제가 노란색으로 친 부분은 main thread가 접근을 하지 못합니다. 이를 visible하지 않다고 합니다.

 

 

 그러면, worker1 thread가 읽어오는 stop이 아닌, 다른 stop에 flag를 업데이트 할 겁니다. 중요한 것은, 이 경우에, worker 1에서 루프는 계속 돈다는 것입니다. 레지스터에 저장된 stop이 업데이트 되지 않았기 때문입니다.

 


 그러면 어떻게 하면 될까요? volatile 키워드를 붙이면 됩니다.

 

 

 아까와 다른 점은 stop에 volatile이 붙었다는 것입니다.

 

 

 실행을 해 보면, 1000번 다 돌고 끝났음을 볼 수 있습니다. 이는 volatile이 최적화를 제외시켜서, 레지스터 대신 메모리에서 접근하게끔 했기 때문입니다. 그런데, 이것은 Thread safe와는 무관한 키워드임을 알 수 있습니다. 단지, 컴파일러의 최적화를 제한한 것일 뿐입니다. 테스트 프로그램을 돌려보면 알 수 있습니다.

 

 

 Worker1에는 sum 변수가 들어 있습니다. Main에서도 Worker1에서도 접근 가능한 공유 변수입니다. Main 스레드에서는 공유변수를 10만번 1씩 감소시킵니다.

 

 

 Worker1은 10만번 증가시킵니다.

 

 

 실행 결과는 위와 같습니다. 이 결과는 volatile과 Thread safe, lock하고는 별개의 키워드임을 보여줍니다. 싱글톤 패턴할 때 한 번 더 언급이 될 듯 하니 알아두면 좋을 듯 싶습니다. 여담으로, 이것은 올해 4월에 스터디 한 건데 8개월이 지난 시점에 올리는 것을 보면 포스팅이 많이 밀리긴 했나 봅니다.