메모리 가시성 문제

  • 멀티스레드에서 어려운 문제 중 하나가 메모리 가시성 문제다.
  • 한 스레드가 변경한 값이 다른 스레드에서는 언제 보이는지에 대한 문제다
  • 무슨 문제이고 왜 발생하고 어떻게 해결할 지 살펴보자.

일반적으로 생각하는 메모리 접근 방식

실제 메모리 접근 방식

  • 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

+ Recent posts