자바 코드를 보면 특정 변수 앞에 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을 붙이면 되기 때문에 간결하게 코드를 작성할 수 있습니다.
즉, 정리하자면
- volatile 대신 synchronized를 사용할 수 있지만, synchronized 대신 volatile을 사용할 수 없습니다.
- synchronized는 변수의 동기화를 위해 사용합니다.
- volatile은 변수의 최신값을 가지고 올 수 있도록 합니다.
※ 참고 ※
- 상수로 선언된 변수(final로 선언된 변수)는 volatile을 붙일 수 없습니다. 어차피 final로 선언되었다는 말은 변하지 않는 값이므로 thread-safe 합니다.
- JVM은 데이터를4byte(=32bit) 단위로 처리합니다. 따라서 int와 int보다 작은 타입들은 한 번에 읽거나 쓰는 것이 가능하므로 volatile을 사용하지 않아도 원자화됩니다. 하지만, long이나 double 타입과 같이 int보다 큰 타입들은 volatile을 통해 원자화 상태로 만들어주어야 원자화가 됩니다.
[참고자료]
https://m.blog.naver.com/jysaa5/221854703163
https://ko.wikipedia.org/wiki/Volatile_%EB%B3%80%EC%88%98
남궁 성, [Java의 정석 3rd Edition], 도우출판, 2016
'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 |