2024-06-28,   조평연

본 포스팅은 자바 키워드중 volatile를 알아보는 내용입니다.

1. volatile 이란?

  • 각 Thread는 Main Memory로 부터 값을 복사해 CPU Cache에 저장하여 작업을 하는데 이때 Multi Thread 환경일 경우 각 Thread가 다른 cpu에서 동작하여 읽기, 쓰기를 반복하다 보면 각자의 CPU Cache의 값과 Main Memory의 값이 다를 수 있습니다. 이를 volatile 키워드를 이용하여 CPU Cache가 아닌 Main Memory에서만 이루어지게 해 동시성 문제를 해결해 주는 키워드라고 볼 수 있습니다.

2. volatile 특징

  • Java 변수를 Main Memory에 저장하겠다는것을 명시합니다.
  • 변수의 값을 read 할때마다 매번 CPU cache에 저장된 값을 가져오지 않고 Main Memory에서 읽습니다.
  • 변수의 값을 write 할때마다 Main Memory 까지도 작성하는 것입니다.

3. 사용 이유

  • 앞서 1번에서 대략 얘기 했지만 요약해 보자면 아래와 같습니다.
  • volatile 변수를 사용하고 있지 않는 MultiThread 어플리케이션에서는 Task를 수행하는 동안 성능 향상을 위해 Main Memory에서 읽은 변수 값을 CPU Cache에 저장하게 됩니다.
  • 만약에 Multi Thread환경에서 Thread가 변수 값을 읽어올 때 각각의 CPU Cache에 저장된 값이 다르기 때문에 변수 값 불일치 문제가 발생하게 되기 때문입니다.


4. 예시

  • SharedObject를 공유하는 두 개의 Thread가 있습니다. Thread-1는 counter 값을 더하고 읽는 연산을 합니다. (Read & Write) Thread-2는 counter 값을 읽기만 합니다. (Only Read)
    public class SharedObject {
      public int counter = 0;
    }
    
  • Thread-1은 counter값을 증가시키고 있지만 CPU Cache에만 반영되어있고 실제로 Main Memory에는 반영이 되지 않았습니다.
  • 그렇기 때문에 Thread-2는 count값을 계속 읽어오지만 0을 가져오는 문제가 발생합니다.


5. 해결방법

  • volatile 키워드를 추가하게 되면 Main Memory에 저장하고 읽어오기 때문에 변수 값 불일치 문제를 해결 할 수 있습니다.
  • Multi Thread 환경에서 하나의 Thread만 read & write하고 나머지 Thread가 read하는 상황에서 가장 최신의 값을 보장합니다.
    public class SharedObject {
      public volatile int counter = 0;
    }
    

6. 예외

  • Thread-1이 값을 읽어 1을 추가하는 연산을 진행 ( 추가하는 연산을 했지만 아직 Main Memory에 반영되기 전 상황 )
  • Thread-2이 값을 읽어 1을 추가하는 연산을 진행 ( 추가하는 연산을 했지만 아직 Main Memory에 반영되기 전 상황 )
  • 위와 같은 상황에서 두 개의 Thread가 1씩 추가하는 연산을 하여 최종결과가 2가 되어야 하는 상황, 하지만 각각 결과를 Main Memory에 반영하게 된다면 1만 남는 상황이 발생하게 됩니다.
  • 즉 하나의 Thread가 아닌 여러 Thread가 write하는 상황에서는 적합하지 않습니다.
  • 여러 Thread가 write하는 상황이면 synchronized를 통해 변수 read & write의 원자성(atomic)을 보장해야 합니다.


7. 언제 쓰면 좋은가?

  • 하나의 Thread가 write하고 나머지 Thread가 읽는 상황인 경우
  • 변수의 값이 최신의 값으로 읽어와야 하는 경우

8. 참고문헌

  • http://tutorials.jenkov.com/java-concurrency/volatile.html

업데이트: