volatile 키워드 의미해당 변수를 main memory에 저장하고 읽어오겠다고 명시하는 키워드
volatile 키워드로 선언한 변수는 모든 읽고 쓰기를 cpu register(cpu cache)에 하지 않고 바로바로 main memory에 하겠다!!!
volatile 변수 값 읽을 때, CPU cache가 아닌 main memory에서 읽어옴volatile 변수 값 쓸 때, CPU cache가 아닌 main memory에 씀
thread가 작업을 시작하게 되면 main memory에서 해당 작업에 필요한 변수들을 자신의 CPU cahce에 복사해놓고 쓴다
thread가 작업하고 있는 시점을 보면, main memory에서 가져온 변수가 cpu cache에 저장된 값과 main memory에 저장되어 있는 값이 다를 수 있다
현대 컴퓨터들은 멀티 코어이기에, 각 thread들은 서로 다른 CPU에서 동시에 실행되고 있다.
thread 1에서 변수를 수정해도 이 수정된 값이 언제 main memory로 반영되고, thread 2는 언제 main memory에서 가져올지 시기를 알지 못한다.
즉, thread 1에서 수정한 변수가 아직 main memory에 반영되지 않았기에 다른 thread들에서는 해당 변수에 대한 최신 값을 보지 못한다 = 가시성 문제 발생!!
volatile 변수는 읽고 쓰기를 main memory에 바로 하기 때문에, 특정 thread가 값을 쓰자마다 다른 thread들은 최신 값을 바로 볼 수 있다
volatile의 특징public class MyClass {
private int years;
private int months
private volatile int days;
public void update(int years, int months, int days){
this.years = years;
this.months = months;
this.days = days;
}
public int totalDays() {
int total = this.days;
total += months * 30;
total += years * 365;
return total;
}
}
update() 메서드에서 days가 수정될 때, 앞서 수정한 years와 months의 값도 같이 바로 main memory에 반영한다.
totalDays() 메서드에서 total += years * 365;로 volatile 변수 읽을 때, main memory에서 읽어 온다
volatile 변수는 바로 main memory에 반영되는건 알겠는데, years랑 months는 volatile 변수도 아닌데 왜 같이 main memory에 반영되는거야????기본적으로 JVM은 성능을 향상하기 위해 sementic이 바뀌지 않는 선에서 알아서 instruction의 순서를 재정렬한다 -> 이걸 instruction reordering이라고 함
근데 위와 같은 상황에서 days만 최신 데이터로 main memory에 업데이트하고, 나머지 years, months는 최신으로 업데이트하지 않으면 데이터 일관성이 유지되지 않는다.
years, months, days는 서로 연관되어 있는 데이터이기에 하나의 변수만 가시성을 유지하는게 좀 이치에 맞지 않다.days만 최신 데이터고 나머지는 최신 데이터가 아니라면 이게 무슨 의미가 있는가...그럼 변수 3개 다 volatile 키워드로 선언하면 되는거 아닌가? 라는 생각이 드는 건 당연하다
근데 뭔가 모든 변수를 다 volatile로 선언해야만 될 것 같은 안좋은 기분이 든다..
그래서 Java에서는 Happens-Before을 보장함으로써, 이를 어느정도 해결했다!!
volatile 변수에 write하기 전의 모든 작업은 해당 write 작업 이후로 재정렬되지 않는다.
volatile 변수 write 기준으로 (여기선 this.days = days; 이 부분) 이전의 read, write는 무조건 volatile 변수 write 이전에 발생한다this.years = years;, this.months = months; 얘네들이 JVM의 instruction reordering으로 인해 this.days = days; 이 instruction 뒤로 갈 일은 절대로 네버 일어나지 않는다!!!volatile 변수를 read 후의 read/write는 작업은 재정렬되어 해당 read 작업 이전으로 재정렬될 수 없다.
volatile 변수 read 이전의 read 작업은 해당 read 이후로 재정렬될 수 있습니다.volatile 변수에 대해서 여러 thread가 동시에 write를 하게 되어도 가시성이 보장될까??우선 가시성은 동시성이랑 다르다!!!
가시성을 보장한다는 말은 한 thread에서 수행된 변경사항을 다른 thread에서 즉각 보이는 것을 보장하는 것
동시성을 보장한다는 말은 여러 thread가 한 리소스(여기선 volatile 변수)에 접근했을 때, race condition이 발생되지 않도록 보장해주는 것
정리하면, 여러 thread가 동시에 write를 진행해도 가시성은 보장되지만 동시성은 보장되지 않는다!!
가시성 보장한다는게 자칫 동시성도 보장해주는 것처럼 느껴지지만 절대 아니다!!!
두 thread가 공유 변수에 대해 읽고 쓰는 경우 volatile로 해결 X → synchronized 처리 해줘야 함
한 개의 thread만 volatitle 변수를 읽고 쓰고, 나머지 thread들은 읽기만 하면 가시성 보장 가능
public class TaskRunner {
private volatile boolean running = true;
public void start() {
new Thread(() -> {
while (running) {
// 반복 작업 수행
}
}).start();
}
public void stop() {
running = false; // 다른 스레드에서 접근하여 상태 변경
}
}
public class ConfigCache {
private volatile Config config;
public void updateConfig(Config newConfig) {
config = newConfig;
}
public Config getConfig()
}
변수의 read&write를 CPU L1 캐시가 아닌 Main Memory에 하기 때문에 비용이 더 발생한다
volatile 변수 때문에 성능을 위한 instruction reordering을 못함
동기화 처리를 해줘야 되기에 성능 하락 가능