반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- Redis
- 운영체제
- Scaffold
- 연습문제
- 코드트리
- pub.dev
- flutter
- AOP
- nGrinder
- 디프만
- C언어
- 부하 테스트
- 코딩 테스트
- c
- Kafka
- 디프만16기
- 코딩
- 자료구조
- 코드 트리
- 코딩테스트
- Oidc
- Kotlin
- java
- OAuth
- kakao
- depromeet
- dip
- Spring
- exception
- Sharding
Archives
- Today
- Total
Nick Dev
[JAVA] volatile ⁉ 본문
반응형
volatile
키워드 의미
- 해당 변수를 main memory에 저장하고 읽어오겠다고 명시하는 키워드
volatile
키워드로 선언한 변수는 모든 읽고 쓰기를 cpu register(cpu cache)에 하지 않고 바로바로 main memory에 하겠다!!!volatile
변수 값 읽을 때, CPU cache가 아닌 main memory에서 읽어옴volatile
변수 값 쓸 때, CPU cache가 아닌 main memory에 씀
기본적인 thread의 처리 방식
- thread가 작업을 시작하게 되면 main memory에서 해당 작업에 필요한 변수들을 자신의 CPU cahce에 복사해놓고 쓴다
- thread가 작업하고 있는 시점을 보면, main memory에서 가져온 변수가 cpu cache에 저장된 값과 main memory에 저장되어 있는 값이 다를 수 있다
✅ volatile 키워드 변수가 필요한 이유!!!
- 현대 컴퓨터들은 멀티 코어이기에, 각 thread들은 서로 다른 CPU에서 동시에 실행되고 있다.
thread 1
에서 변수를 수정해도 이 수정된 값이 언제 main memory로 반영되고,thread 2
는 언제 main memory에서 가져올지 시기를 알지 못한다.- 즉,
thread 1
에서 수정한 변수가 아직 main memory에 반영되지 않았기에 다른 thread들에서는 해당 변수에 대한 최신 값을 보지 못한다 = 가시성 문제 발생!! - volatile 변수는 읽고 쓰기를 main memory에 바로 하기 때문에, 특정 thread가 값을 쓰자마다 다른 thread들은 최신 값을 바로 볼 수 있다
volatile
의 특징
가시성 보장
- 기본적으로 non-volatile 변수(일반적으로 우리가 아는 그런 변수)는 멀티 스레딩 환경에서 가시성이 보장되지 않는다
Full volatile visibility guarantee
- 완전한 휘발성 가시성 보장
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에 반영되는거야????
- 이게 바로 happens-before-gurantee 라는 것!
✅ happens-before-gurantee 이해를 위한 배경 지식
- 기본적으로 JVM은 성능을 향상하기 위해 sementic이 바뀌지 않는 선에서 알아서 instruction의 순서를 재정렬한다 -> 이걸 ** instruction reordering**이라고 함
- 근데 위와 같은 상황에서
days
만 최신 데이터로 main memory에 업데이트하고, 나머지years
,months
는 최신으로 업데이트하지 않으면 데이터 일관성이 유지되지 않는다.- 왜냐면
years
,months
,days
는 서로 연관되어 있는 데이터이기에 하나의 변수만 가시성을 유지하는게 좀 이치에 맞지 않다. days
만 최신 데이터고 나머지는 최신 데이터가 아니라면 이게 무슨 의미가 있는가...
- 왜냐면
- 그럼 변수 3개 다
volatile
키워드로 선언하면 되는거 아닌가? 라는 생각이 드는 건 당연하다 - 근데 뭔가 모든 변수를 다
volatile
로 선언해야만 될 것 같은 안좋은 기분이 든다.. - 그래서 Java에서는 Happens-Before을 보장함으로써, 이를 어느정도 해결했다!!
✅ happens-before-gurantee 특징!!
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 변수 write 이후의 read/write는 해당 write 이전으로 재정렬될 수 있다
- 즉,
volatile
변수를 read 후의 read/write는 작업은 재정렬되어 해당 read 작업 이전으로 재정렬될 수 없다.volatile
변수 read 이전의 read 작업은 해당 read 이후로 재정렬될 수 있습니다.
이쯤 되면 또 의문이 들 수 있다.. 만약 volatile
변수에 대해서 여러 thread가 동시에 write를 하게 되어도 가시성이 보장될까??
- 우선 가시성은 동시성이랑 다르다!!!
- 가시성을 보장한다는 말은 한 thread에서 수행된 변경사항을 다른 thread에서 즉각 보이는 것을 보장하는 것
- 동시성을 보장한다는 말은 여러 thread가 한 리소스(여기선
volatile
변수)에 접근했을 때, race condition이 발생되지 않도록 보장해주는 것 - 정리하면, 여러 thread가 동시에 write를 진행해도 가시성은 보장되지만 동시성은 보장되지 않는다!!
- 여러 thread들 중에 어쨋든 한 thread의 값이 결국 main memory에 저장될 것임 -> 이 값을 모든 thread에서 바로 볼 수 있기에 결국 가시성은 보장됨
- 하지만 여러 thread의 변경사항 중 결국 어떤 것이 저장될지는 모르기에 동시성은 보장되지 않음
가시성 보장한다는게 자칫 동시성도 보장해주는 것처럼 느껴지지만 절대 아니다!!!
그럼 언제 volatile 키워드를 사용할까??
- 두 thread가 공유 변수에 대해 읽고 쓰는 경우
volatile
로 해결 X →synchronized
처리 해줘야 함 - 한 개의 thread만
volatitle
변수를 읽고 쓰고, 나머지 thread들은 읽기만 하면 가시성 보장 가능
예시 1 - 다른 thread 실행을 제어할 때
public class TaskRunner {
private volatile boolean running = true;
public void start() {
new Thread(() -> {
while (running) {
// 반복 작업 수행
}
}).start();
}
public void stop() {
running = false; // 다른 스레드에서 접근하여 상태 변경
}
}
예시 2 - 가끔 변경되지만 자주 읽힐 때
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을 못함- 동기화 처리를 해줘야 되기에 성능 하락 가능
반응형
'Java' 카테고리의 다른 글
[JAVA] About 제네릭 (0) | 2024.12.29 |
---|---|
[JAVA] CAS 알고리즘이란?! (0) | 2024.12.11 |
[JAVA] Thread vs Process (0) | 2024.12.11 |
[JAVA] 객체 지향의 4대 특성 - 캡!상추다 (0) | 2024.12.11 |
[JAVA] HashMap의 내부 구현 방식 (0) | 2024.12.11 |