- [Java 정리] Thread 62022년 08월 22일
- starryeye
- 작성자
- 2022.08.22.:07
이미 알던 지식이지만, 기본으로 돌아가서.. Java의 관점에서 한번 정리해보자.
volatile
멀티 코어 프로세서 환경에서는
코어마다 별도의 캐시(레지스트리)를 가지고 있다.
코어는 메모리에서 읽어온 값을 캐시에 저장하고 캐시에서 값을 읽어서 작업한다.
다시 같은 값을 읽을 때는 캐시에 존재하지 않을 경우에만 메모리에서 읽어 온다.
그러면..
A코어에 의해 메모리에 저장된 변수의 값이 변경 되었는데.. B코어의 캐시에 저장된 값이 갱신 되지 않았다면..
데이터가 다르므로.. 프로그램은 예상치 못한 흐름으로 동작한다.
해결법은..
변수 앞에 volatile 키워드를 붙이면 코어가 변수의 값을 읽을 때 항상 메모리에서 읽어오게 된다.
따라서.. 캐시와 메모리간의 값의 불일치가 해결된다.
volatile은 해당 변수에 대해 Read Write가 원자화 된다.
JVM은 데이터를 4byte 단위로 처리한다.
따라서 int와 int보다 작은 타입은 한번에 읽거나 쓰는 것이 가능하다.
(단 하나의 명령어)
하지만..
크기가 8byte인 long, double은 하나의 명령어로 Read/Write가 불가능 하기 때문에..
변수의 Read/Write 과정에서 다른 쓰레드가 끼어들 여지가 생긴다.
그럴때 volatile 키워드를 사용한다.
<참고>
volatile은 "변수"에 대해 읽기와 쓰기가 원자화 되는 것이다.
"여러 코드 문장"을 원자화한 synchronized 블럭을 이용하여
쓰레드의 동기화를 구현한 것과 구분해야한다.
volatile long balance; int getBalance() { return balance; } synchronized void withdraw(int money) { if(balance >= money) balance -= money; }
위 코드에서 개발자의 의도는 돈이 인출 되는 도중에는 잔고를 확인 할 수 없게.. 하자였다고 치자.
위 코드에서는 getBalance() 메서드에서 synchronized 키워드를 사용하지 않았다..
이는 잘못된 개발 코드이다.
balance 변수에 volatile 키워드가 붙어있어서 단순히 원자화 되었으니
(메서드 단위의)동기화가 되겠거니.. 라는 생각은 큰 오산이다.
쓰레드 A가 락을 획득하고 withdraw() 메서드가 동작되는 상황에서
getBalance()가 쓰레드 B에 의해 호출되면.. volatile 변수기 때문에 "변수"의 쓰기와 읽기만 원자화된다.
실제로..
돈이 인출되기 전에 getBalance가 수행될 수도..
돈이 인출된 후에 getBalance가 수행될 수도.. 있다..
따라서, getBalance()메서드에 synchronized 키워드를 붙여줘야 한다.
'Java' 카테고리의 다른 글
불변 객체, lombok @Value 와 Java Record (0) 2023.05.07 [Java 정리] ThreadLocal (0) 2022.10.19 [Java 정리] Thread 5 (0) 2022.08.22 [Java 정리] Thread 4 (0) 2022.08.22 [Java 정리] Thread 3 (0) 2022.08.19 다음글이전글이전 글이 없습니다.댓글