자바에서는 캐싱에 의한 문제를 방지하기 위해 volatile을 쓴다. 이게 무슨 말이냐
쓰레드를 실행하는 CPU의 각 코어는 캐시를 가지고 있다.
메모리에서 값을 읽기전에 더 빠른 접근이 가능한 캐시에 있는 지 확인하고 메모리에 접근한다.
따라서 메모리와 캐시가 서로 저장된 값이 달라 변수 값 불일치 문제가 생길 수 있다.
이 캐싱 문제를 해결하기 위해서 volatile이라는 키워드가 쓰인다.
volatile은 변수 값을 Read 할 때마다 메인 메모리에서 읽고
Write 할 때마다 메모리 까지 작성 하도록 하는 것이다.
package Thread.Sync;
public class Cache {
static boolean stop = false;
public static void main(String[] args) {
new Thread(() -> {
while (!stop) {
}
System.out.println("- - - 종료 - - -");
}).start();
try { Thread.sleep(1000);
} catch (InterruptedException e) {}
stop = true;
System.out.println(stop);
}
}
위에는 캐싱에 의한 문제를 확인할 수 있는 코드다.
우선 while 문이 stop변수 값이 false일 동안 계속되는 작업을 하는 하나의 스레드가 실행을 하고
메인 스레드는 1초 있다가 stop 변수 값을 true로 변경한다.
논리적으로는 1초 있다가 while문이 끝나고 실행이 끝나야 하지만 끝나지 않는다.
이를 통해 한 쓰레드가 값을 바꿔도 다른 쓰레드의 캐시가 비워지지 않는 이상 그 이전 값을 참조할 수도 있음을 보여준다.
해결방법은 2가지다.
volatile static boolean stop = false;
첫번째는 volatile 키워드를 통해 stop 변수가 값이 업데이트 될 때마다 메모리에 업데이트 되도록 하는 것이다.
이는 멀티쓰레딩 환경에서 캐싱에 의한 문제를 방지 해준다.
그치만 volatile은 동기화와는 다르다.
동기화는 변수에 대하여 다른 스레드들의 동시 접근을 제어하는 반면 volatile은 값 변경에 대해 확실히 확인 시켜주는 것에 초점이 있다.
package Thread.Sync;
public class Cache {
static boolean stop = false;
synchronized public static boolean isStop() {
return stop;
}
synchronized public static void setStop(boolean stop) {
Cache.stop = stop;
}
public static void main(String[] args) {
new Thread(() -> {
while (!isStop()) {
}
System.out.println("- - - 종료 - - -");
}).start();
try { Thread.sleep(1000);
} catch (InterruptedException e) {}
setStop(true);
System.out.println(stop);
}
}
두번째 방법이다. volatile 대신 동기화된 getter와 setter메소드를 사용하여 변수 값을 읽어오고 쓰는 것이다.
제대로 파는 자바 (Java) - 얄코 강의를 들으면서 정리했습니다.
'Java&SpringBoot' 카테고리의 다른 글
자바 빌더 패턴이란?(Java,기초) (2) | 2024.03.15 |
---|---|
NPE, Optional (Java,기초) (0) | 2024.03.08 |
오류와 예외처리(Java,기초) (0) | 2024.03.07 |