새로운 내용을 공부할 때
새로운 내용의 공부를 시작할 때 용어의 정의를 이해하지 못하거나 정확하게 알지 못한다면 그 용어가 포함된 문장을 이해하지 못합니다.
작은 단어 하나가 내용을 이해하지 못하게 하기 때문에 용어를 정확하게 이해하는 것이 중요합니다.
TIL) Volatile 동시성의 가벼운 해결사
📌 2025-03-18 TIL
오늘의 학습 주제
- 자바에서 volatile 키워드는 어떤 목적으로 사용될까?
학습 개요
컴파일러나 프로세서, 하드웨어 레벨에서 프로그램을 실행할 때 최적화를 합니다.
최적화를 하는 방식 중에서 명령 재배치(reordering), 캐싱(caching)이 발생할 수 있습니다.
이때 개발자가 예측한 방식과 다르게 동작하여 예상하지 못한 공유자원의 상태가 다르게 보일 수 있습니다.
동일한 메모리 주소의 값을 사용하는 경우나 명령 재배치로 인해 예상하지 못한 값이 출력되는 것을 방지하기 위해 자바에서는 volatile 키워드를 제공합니다.
학습 목적
자바 백엔드 개발자가 volatile
를 학습하는 이유는 메모리 가시성과 명령 재배치로 인한 동시성 문제를 이해할 수 있습니다.
또한 단일 쓰레드가 값을 쓰고 다중 쓰레드가 읽기만 하는 경우에는 성능 저하 없이 가시성을 보장하여 동시성을 관리할 수 있는 유용한 키워드입니다.
가시성이란
CPU는 작업을 빠르게 하기 위해서 쩌 ~ 멀리 있는 메모리 정보를 한번 읽고난 뒤 자기 뒷자리에 보관합니다.(캐시 메모리 1, 2, 3) 빠르게 연산할 때마다 메모리에 반영이 될 수도 있고 안될 수도 있기 때문에 여러 쓰레드를 여러 CPU에서 작업을 하고 공유자원에 대해 연산을 하는 경우 동시성 문제가 발생할 수 있습니다.
이것을 가시성 문제라고 하며 이 문제를 해결하기 위해서 volatile 는 소리를 지릅니다. 최신 정보 갱신 되었으니까 갱신하세요 !!
CPU는 자기 뒷자리가 아닌 쩌~ 멀리있는 메모리 책상에서 정보를 읽고 씁니다.
모든 동시성 문제는 해결하지 못한다.
여러 쓰레드가 동시에 쓰고 , 읽는 경우에는 volatile 키워드는 한계가 있습니다.
읽을 때 최신 정보를 읽게 할 뿐이지 이미 읽어간 정보를 다시 읽게 하는게 아니기 때문입니다.
동시에 여러 쓰레드가 최신 정보를 읽고 동시에 수정을 하게 된다면 race condition
이 발생할 수 있습니다.
다만 하나의 쓰레드가 쓰기만하고, 나머지 쓰레드는 읽기만 한다면 동시성 문제를 제어하는 여러 키워드보다 성능 저하없이 동시성 문제를 해결해줄 수 있습니다.
원자성 연산에는 한계가 있다.
읽고 쓰기까지 한꺼번에 해결해야하는 원자성은 해결할 수 없습니다.
상호배제 문제를 해결하지 않고 가시성 문제만 해결해주는 키워드이기 때문입니다.
원자성 연산이라는 것은 읽고 쓰는 두 개의 연산을 하나의 작업으로 처리하는 것을 말합니다.
volatile int counter = 0;
public void increment() {
counter++; // 원자성 없음: race condition 발생 가능
}
재배치를 방지한다.
프로세서, 컴파일러, CPU는 연산의 속도를 높이기 위해서 코드의 순서를 임의로 변경합니다.
이때 volatile 키워드 기준으로 위 아래 코드가 순서가 변경되지 않도록 보장해줍니다
예를 들어,
int topNum = 10;
boolean topBoolean = false;
volatile String stand = "기준";
int bottomNum = 12;
boolean bottomBoolean = true;
stand를 기준으로 위에 변수와 아래 변수의 순서는 변경되지 않습니다.
다만, top끼리 bottom 끼리 재배치는 발생할 수 있습니다.
일관된 동작을 보장하려면
멀티 쓰레드 환경에서 일관된 동작을 보장하려면 두 가지가 필요합니다.
- 상호배제 - 동시성 문제를 제어하며 동일한 자원에 접근할 경우 하나의 쓰레드만 읽기/쓰기만 가능하도록 보장합니다.
- 가시성 - 한 스레드가 수정한 내용을 다른 쓰레드에서 즉시 확인이 가능합니다.
상호 배제를 할 때에 volatile 키워드는 동시성 문제를 제어하지는 못하며 가시성 문제를 해결한다는 것입니다.
댓글남기기