Volatile
Aug 20, 2024
volatile
은 Java에서 변수의 값을 CPU 캐시가 아닌 메인 메모리에서 직접 읽고 쓰도록 강제하는 키워드입니다. 멀티스레드 환경에서 변수의 가시성(Visibility) 문제를 해결하기 위해 사용됩니다.1. 가시성 문제 (Visibility Issue)
멀티스레드 환경에서는 여러 스레드가 동시에 변수에 접근할 수 있습니다. 자바의 기본 메모리 모델에서는 각 스레드가 성능을 위해 변수 값을 CPU 캐시에 저장하고 사용합니다. 이 때문에 한 스레드가 변수 값을 변경해도 다른 스레드는 여전히 자신의 캐시에 저장된 오래된 값을 참조할 수 있습니다. 이러한 상황을 가시성 문제라고 합니다.
2. volatile
의 역할
volatile
키워드는 이 가시성 문제를 해결하는 데 사용됩니다. volatile
로 선언된 변수는 항상 메인 메모리에서 읽고 쓰기 때문에, 한 스레드가 volatile
변수를 변경하면 다른 스레드들은 즉시 그 변경된 값을 볼 수 있습니다.public class VolatileExample {
private volatile boolean flag = true;
public void run() {
while (flag) {
// 무한 루프
}
System.out.println("Thread stopped.");
}
public void stop() {
flag = false; // 다른 스레드가 즉시 이 변경을 감지할 수 있음
}
public static void main(String[] args) throws InterruptedException {
VolatileExample example = new VolatileExample();
Thread thread = new Thread(example::run);
thread.start();
Thread.sleep(1000); // 1초 후
example.stop(); // flag 값을 false로 변경
}
}
위 코드에서
flag
변수는 volatile
로 선언되어 있습니다. run()
메서드의 무한 루프는 flag
값이 true
일 때만 계속 실행되는데, stop()
메서드를 호출하면 flag
가 false
로 변경됩니다. 이 변경 사항은 즉시 다른 스레드에 반영되어, run()
메서드의 무한 루프가 종료됩니다.3. volatile
의 한계
- 원자성 보장 불가:
volatile
은 가시성 문제는 해결하지만, 원자성(Atomicity)은 보장하지 않습니다. 예를 들어,volatile
변수에 대한 복합 연산(예:count++
)은 여전히 안전하지 않습니다. 복합 연산은 여러 단계를 거치며, 각 단계에서 다른 스레드가 변수 값을 변경할 수 있기 때문입니다. 이러한 경우에는synchronized
나Lock
을 사용해야 합니다.
- 성능:
volatile
변수는 항상 메모리에서 읽고 쓰기 때문에, 일반 변수에 비해 성능이 다소 저하될 수 있습니다. 하지만 이는 가시성을 보장하는 대가로서 받아들여야 합니다.
4. volatile
사용 사례
- 상태 플래그:
volatile
은 간단한 상태 플래그 또는 종료 플래그를 관리할 때 자주 사용됩니다.
- 이벤트 플래그: 이벤트 발생 여부를 다른 스레드가 즉시 알 수 있도록 하는 경우에도 사용됩니다.
- 단일 읽기/쓰기 변수: 한 스레드가 변수를 갱신하고 다른 스레드가 이를 읽기만 하는 경우,
volatile
로 선언하면 추가적인 동기화 없이도 가시성을 보장할 수 있습니다.
5. 결론
volatile
은 멀티스레드 프로그래밍에서 변수의 가시성을 보장하는 중요한 키워드입니다. 스레드가 공유하는 변수의 최신 상태를 즉시 반영해야 할 때 사용되며, 가시성 문제를 쉽게 해결할 수 있습니다. 하지만 원자성이 필요한 경우에는 volatile
만으로는 충분하지 않으며, synchronized
와 같은 추가적인 동기화 방법을 사용해야 합니다.Share article