[자바 프로그래밍 기초] Volatile 변수 알아보기

[자바 프로그래밍 기초] Volatile 변수 알아보기


자바 변수, Volatile 변수

자바 언어에서는 volatile 변수로 약간 다른 형태의 좀 더 약한 동기화 기능을 제공하는데, 다시 말해 volatile로 선언된 변수의 값을 바꿨을 때 다른 스레드에서 항상 최신 값을 읽어갈 수 있도록 해준다.


특정 변수를 선언할 때 volatile 키워드를 지정하면, 컴파일러와 런타임 모두 '이 변수는 공유해 사용하고, 따라서 실행 순서를 재배치해서는 안 된다'고 이해한다. volatile로 지정된 변수는 프로세서의 레지스터에 캐시 되지도 않고, 프로세서 외부의 캐시에도 들어가지 않기 때문에 volatile 변수의 값을 읽으면 항상 다른 스레드가 보관해둔 최신의 값을 읽어갈 수 있다.


volatile로 지정한 변수는 읽기와 쓰기 연산을 각각 get과 set 메소드에 비교해 보면 SynchronizedInteger 클래스와 대략 비슷한 형태로 작동한다고 이해할 수 있겠다(SynchronizedInteger 클래스에서 확보할 수 있는 메모리 가시성이 volatile 변수의 가시성보다 훨씬 확실한 방법이다.).

volatile 변수를 사용할 때에는 아무런 락이나 동기화 기능이 동작하지 않기 때문에 synchronized를 사용한 동기화보다는 아무래도 강도가 약할 수밖에 없다(요즘 대부분 프로세서에서는 volatile 변수를 읽는 연산이 volatile이 아닌 변수를 읽는 시간보다 아주 약간 더 느릴 뿐인 경우가 많다.).


실제로 volatile 변수가 갖는 가시성 효과는 volatile로 지정된 변수 자체의 값에 대한 범위보다 약간 확장되어 있다.


스레드 A가 volatile 변수에 값을 써넣고 스레드 B가 해당 변수의 값을 읽어 사용한다고 할 때, 스레드 B가 volatile 변수의 값을 스레드 B도 모두 볼 수 있다는 점이다.


따라서 메모리 가시성의 처지에서 본다면 volatile 변수를 사용하는 것과 synchronized 키워드로 특정 코드를 묶는 게 비슷한 효과가 있고, volatile 변수의 값을 읽고 나면 synchronized 블록에 진입하는 것과 비슷한 상태에 해당한다.


자바 변수 volatile 변수[Java 강좌] Variable 원리


어쨌거나 메모리 가시성에 효과가 있긴 하지만 그렇다고 volatile 변수에 너무 의존하지 않는 게 좋다. volatile 변수만 사용해 메모리 가시성을 확보하도록 작성한 코드는 synchronized로 직접 동기화한 코드보다 훨씬 읽기가 어렵고, 따라서 오류가 발생할 가능성도 크다.


동기화하고자 하는 부분을 명확하게 볼 수 있고, 구현하기가 훨씬 간단한 경우에만 volatile 변수를 활용하자. 반대로 작은 부분이라도 가시성을 추론해봐야 하는 경우는 volatile 변수를 사용하지 않는 것이 좋다.


volatile 변수를 사용하는 적절한 경우는, 일반적으로 변수에 보관된 클래스의 상태에 대한 가시성을 확보하거나 중요한 이벤트(초기화, 종료 등)가 발생했다는 등의 정보를 정확하게 전달하고자 하는 경우 등이 해당한다. 예제에서 volatile 키워드를 사용하는 일반적인 때를 볼 수 있는데, 특정 변수의 값을 확인해 반복문을 빠져나갈 상황인지 확인하는 예이다.


예제의 스레드는 오래전부터 사람들이 잠이 오지 않을 때 양의 마릿수를 세던 방법을 사용하도록 코딩되어 있다. 우리가 원하는 양의 마릿수를 세는 기능이 제대로 동작하려면 asleep 변수가 반드시 volatile로 선언되어 있어야 한다. volatile로 지정하지 않으면 다른 스레드가 asleep 변수의 값을 바꿨을 때, 변경됐다는 상태를 확인하지 못할 수도 있다.


자바 변수 volatile 변수 알아보기[Java 강좌] Variable 원리


물론 volatile을 지정하는 대신 synchronized를 사용해 락을 걸어도 같은 문제를 예방할 수 있지만, 코드가 그다지 보기 좋지 않을 게 분명하다.


1
2
3
4
volatile boolean asleep;
...
    while (!asleep)
        countSomeSheep();
cs


보다시피 volatile 변수는 굉장히 간편하게 사용할 수 있지만 제약 사항도 있다.


일반적으로 예제의 asleep과 같이 작업을 완료했다거나, 인터럽트가 걸리거나, 기타 상태를 보관하는 플래그 변수에 volatile 키워드를 지정한다. 주의를 좀 더 기울여야 하긴 하지만, 다음과 같은 상황에서도 volatile 변수를 사용해 효과를 볼 수 있다.


Volatile 변수 자바[Java 강좌] Variable 원리


하나의 스레드에서만 사용한다는 보장이 없는 상태라면, volatile 연산자의 기본적인 능력으로는 장가 연산자(count++)를 사용한 부분까지 동기화를 맞춰 주지는 않는다(단일 연산 변수를 사용하면 읽고, 변경하고, 쓰는 부분에 모두 단일 연산을 보장하기 때문에 '좀 더 나은 volatile 변수'로 사용할 수 있다.).


락을 사용하면 가시성과 연산의 단일성을 모두 보장받을 수 있다. 하지만 volatile 변수는 연산의 단일성은 보장하지 못하고 가시성만 보장한다. 정리하자면, volatile 변수는 다음과 같은 상황에서만 사용하는 것이 좋다.


1. 변수에 값을 저장하는 작업이 해당 변수의 현재 값과 관련이 없거나 해당 변수의 값을 변경하는 스레드가 하나만 존재.

2. 해당 변수가 객체의 불변조건을 이루는 다른 변수와 달리 불변조건에 관련되어 있지 않음.

3. 해당 변수를 사용하는 동안에는 어떤 경우라도 락을 걸어 둘 필요가 없는 경우.


[자바 프로그래밍 기초] Volatile 변수 알아보기

이 글을 공유하기

댓글(0)

Designed by JB FACTORY