메모리 가시성 문제
- 멀티스레드에서 어려운 문제 중 하나가 메모리 가시성 문제다.
- 한 스레드가 변경한 값이 다른 스레드에서는 언제 보이는지에 대한 문제다
- 무슨 문제이고 왜 발생하고 어떻게 해결할 지 살펴보자.
일반적으로 생각하는 메모리 접근 방식
실제 메모리 접근 방식
- main 스레드가 runFlag = false 실행하면,
- main 스레드를 실행하는 CPU 코어의 캐시 메모리의 runFlag = false 부터 반영한다.
- 그래서 메인 메모리의 runFlag 값이 즉시 반영되지 않는다!
CPU 캐시 메모리
- 캐시 메모리를 사용하면 CPU 처리 성능을 개선할 수 있다.
- 코어1 캐시 메모리에 있는 runFlag 의 값이 언제 메인 메모리에 반영될까?
- 메인 메모리에 변경된 runFlag 값이 언제 CPU 코어2의 캐시 메모리에 반영될까?
→ 둘 다 “ 알 수 없다.” CPU의 설계 방식에 따라 다르다.
- 주로 컨텍스트 스위칭이 될 때, 캐시 메모리가 갱신된다.
- 하지만, 이것이 갱신을 보장하는 것은 아니다.
값을 읽을 때, 값을 쓸 때 모두 메인 메모리에 직접 접근하자!
자바에서는 volatile 키워드로 이런 기능을 제공한다.
volatile 키워드 적용하기
- 캐시 메모리 접근하지 말고, 메인 메모리 접근해!
public class VolatileFlagMain {
public static void main(String[] args) {
MyTask task = new MyTask();
Thread t = new Thread(task, "work");
log("runFlag = " + task.runFlag);
t.start();
sleep(1000);
log("runFlag 변경 시도");
task.runFlag = false;
log("runFlag = " + task.runFlag);
log("main 종료");
}
static class MyTask implements Runnable {
volatile boolean runFlag = true;
@Override
public void run() {
log("task 시작!");
while(runFlag) {
// runFlag 가 false 되면 탈출하자
}
log("task 종료");
}
}
}
- runFlag 변수를 false 바꾸는 순간 즉시 메인 메모리에 반영한다.
- 여러 스레드에서 같은 값을 읽고 써야 한다면, volatile 키워드를 붙이자.
- 단, 캐시 메모리를 쓸 때보다는 성능이 느려지는 단점이 있기 때문에 꼭 필요한 곳에서만 사용해야 한다.
728x90
'프로그래밍 > JAVA' 카테고리의 다른 글
JVM, GC (0) | 2025.04.10 |
---|---|
synchronized (0) | 2025.04.03 |
스레드 생명 주기 (0) | 2025.04.03 |
스레드 생성과 실행 (0) | 2025.04.03 |
List (0) | 2025.03.28 |