본문 바로가기

Java

volatile 키워드

728x90

자바 코드를 보면 특정 변수 앞에 volatile이라는 키워드가 붙어져 있는 경우를 볼 수 있습니다. volatile 키워드가 무엇이고 왜 사용되는지에 대해서 해당 포스팅을 작성하였습니다. 자유롭게 피드백해 주시면 감사하겠습니다!!


volatile 키워드

필요한 이유

먼저, volatile 키워드가 무엇인지에 대하여 설명하기 전에 왜 volatile 키워드가 필요한지 그 배경에 대해서 알아보겠습니다.

 

싱글 코어 프로세서가 장착된 컴퓨터가 아닌, 멀티 코어 프로세서로 돌아가는 컴퓨터에서는 코어마다 별도의 캐시를 가지고 있습니다. 코어는 메모리에서 어떤 값을 읽어와서 캐시에 저장한 후, 캐시에서 값을 읽어서 작업합니다. 해당 값이 필요할 때 우선 캐시에 값이 저장되어 있는지 확인한 후, 없으면 메모리에서 값을 읽어옵니다. 

이 과정에서, 메모리에서는 해당 변수의 값이 변경되었는데, 캐시에는 변경된 값이 반영되지 않아 메모리에 저장된 값과 캐시에 저장된 값이 다르게 되는 문제가 발생할 수 있습니다. 이러한 상황을 방지하고자 사용하는 것이 volatile 키워드 입니다.


volatile 키워드란

변수 앞에 volatile을 붙임으로써, 코어가 변수의 값을 읽어올 때 캐시가 아닌 메모리에서 읽어도록 하는 역할을 하는 키워드라고 할 수 있습니다. 즉, 컴파일러의 최적화를 방지합니다.

또한 volatile를 붙이면 해당 변수에 대한 읽거나 쓰기가 원자화되어 다른 쓰레드가 끼어들지 못하도록 설정하게 됩니다. 


volatile과 synchronized

volatile을 이용하면 해당 변수가 읽기/쓰기에 대하여 원자화된다고 하였습니다. synchronized 블록도 일종의 원자화 역할을 합니다. 즉, synchronized 블록은 여러 문장을 원자화 함으로써 쓰레드의 동기화를 구현한 것이라고 보면 됩니다. 이와 달리, volatile은 읽기 쓰기 원자화 일뿐 동기화는 아니라는 것에 주의해야 합니다.

 

아래 코드를 보면, var 변수에 volatile이 선언되었다고 즉, var 변수가 원자화되었다고 이 값을 읽어서 반환하는 메서드인 getVar()을 동기화할 필요가 없다고 생각하면 안 된다는 것입니다. getVar()을 synchronized로 동기화하지 않으면, plusOne() 메서드가 수행되고 있는 와중에도 getVar() 메서드를 다른 쓰레드가 호출하는 것이 가능하게 되기 때문에 원하지 않는 값을 얻을 수 있기 때문입니다.


volatile long var; 

synchronized long getVar() {return var;}
synchronized void plusOne() {var++;}

 

또한, 쓰레드 동기화를 위한 synchronized 블록을 이용해도 volatile과 같이 메모리와 캐시 간의 불일치를 방지하는 효과를 얻을 수 있습니다. 왜냐하면, synchronized 블록으로 쓰레드가 들어갈 때와 나갈 때 자동으로 캐시와 메모리 간의 동기화가 이루어지기 때문입니다. 그래서 synchronized로 특정 변수를 사용하는 영역을 감쌀 수도 있습니다. 하지만 volatile을 이용하면 변수를 선언할 때 간단하게 volatile을 붙이면 되기 때문에 간결하게 코드를 작성할 수 있습니다.

 

즉, 정리하자면

  1. volatile 대신 synchronized를 사용할 수 있지만, synchronized 대신 volatile을 사용할 수 없습니다. 
  2. synchronized는 변수의 동기화를 위해 사용합니다.
  3. volatile은 변수의 최신값을 가지고 올 수 있도록 합니다.

※ 참고 ※

  1. 상수로 선언된 변수(final로 선언된 변수)는 volatile을 붙일 수 없습니다. 어차피 final로 선언되었다는 말은 변하지 않는 값이므로 thread-safe 합니다.
  2. JVM은 데이터를4byte(=32bit) 단위로 처리합니다. 따라서 int와 int보다 작은 타입들은 한 번에 읽거나 쓰는 것이 가능하므로 volatile을 사용하지 않아도 원자화됩니다. 하지만, long이나 double 타입과 같이 int보다 큰 타입들은 volatile을 통해 원자화 상태로 만들어주어야 원자화가 됩니다.

 

[참고자료]

https://m.blog.naver.com/jysaa5/221854703163

 

[Java] volatile - 개념

volatile - 멀티 스레딩 환경에서 동기화를 해주는 키워드이다. - 컴파일러가 특정 변수에 대해 옵티마이져...

blog.naver.com

https://ko.wikipedia.org/wiki/Volatile_%EB%B3%80%EC%88%98

 

volatile 변수 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. C/C++ 프로그래밍 언어에서 이 키워드는 최적화 등 컴파일러의 재량을 제한하는 역할을 한다. 개발자가 설정한 개념을 구현하기 위해 코딩된 프로그램을 온전히

ko.wikipedia.org

남궁 성, [Java의 정석 3rd Edition], 도우출판, 2016

728x90
반응형

'Java' 카테고리의 다른 글

자바의 스트림(stream)  (0) 2023.11.05
자바의 람다(Lambda)  (0) 2023.11.01
Lock과 Condition (await()과 signal(),signalAll())  (2) 2023.10.29
wait()과 notify(), notifyAll()  (2) 2023.10.29
synchronized를 이용한 쓰레드의 동기화  (2) 2023.10.29