public class VolatileFlagMain {
public static void main(String[] args) {
MyTask task = new MyTask();
Thread t = new Thread(task, "work");
log("runFlag = " + task.runFlag);
t.start();
sleep(1000);
log("runFlag false 변경 시도");
task.runFlag = false; //false 이기 때문에 task 종료?? -> 자바가 안끝남
log("runFlag = " + task.runFlag);
log("main 종료");
}
static class MyTask implements Runnable {
//boolean runFlag = true;
volatile boolean runFlag = true;
@Override
public void run() {
log("task 시작");
while (runFlag) {
//runFlag false 변경시 탈출
//work Thread가 빠져나오지 못함
//volatile 사용시 Memmory에서 변경 된 값 Thread가 바로 볼 수 있어야 한다.
}
log("task 종료");
}
}
}
runFlag을 사용해 스레드 작업 종료
boolean runFlag = true;을 사용했을때
main 스레드는 종료된 것을 확인 할 수 있지만, while 스레드는 종료되지 않을 것을 볼 수 있다.

실행되는 예상 결과는 main 스레드 종료시, task 스레드도 종료 될 것이라고 예상
하지만 main은 종료되었지만, task 스레드는 종료되지 않은 것을 확인 할 수 있음
메모리 가시성 문제가 발생하기 때문에 동시에 종료되지 않는다.
내 머리속 메모리 접근 방식

실제 메모리 접근 방식

여기서 핵심은 캐시 메모리에 runFlag 값만 반영, 메인 메모리에 이 값이 즉시 반영된다고 보기는 어렵다.
그렇다면 캐시 메모리의 runFlag의 값이 언제 메인 메모리에 반영??
알수 없다. 그렇다면 메인 메모리 또한 알 수 없다.
멀티 스레드 환경에서 한 스레드가 변경한 값이 다른 스레드에서 언제 보이는가?? 메모리 가시성
캐시 메모리를 사용하면 CPU 성능은 개선 가능, 하지만 성능 보다는 여러 스레드에서 같은 시점에 정확히 같은 데이터를 보는 것이 중요 할 수도 있다.
volatile boolean runFlag = true;
runFlag = false 변경되자마자 task 종료 되는 것을 확인 할 수 있다.

단 성능 이슈가 있기 때문에 필요한 곳에다가만 사용하는 것이 좋다.
public class VolatileCountMain {
public static void main(String[] args) {
MyTask task = new MyTask();
Thread t = new Thread(task, "work");
t.start();
sleep(1000);
task.flag = false;
log("flag = " + task.flag + " , count = " + task.count + " in main");
}
static class MyTask implements Runnable {
//boolean flag = true;
//long count;
volatile boolean flag = true;
volatile int count;
@Override
public void run() {
log("task 시작");
while (flag) {
count++;
//1억번에 한번씩 출려 5
if (count % 1000_000_000 == 0) {
log("flag = " + flag + " , count = " + count + " in while");
}
}
log("flag = " + flag + " , count = " + count + " 종료");
}
}
//main과 work의 확인한 시점의 숫자가 다르다.
}
main 스레드가 flag를 변경하는 시점에 work 스레드도 flag 값을 변경 한다는 것을 정확히 알 수 있다.
멀티스레드 환경엣 한 스레드가 변경한 값이 다른 스레드에서 언제 보이는지 대한 것을 메모리 가시성
멀티 스레드 프로그래밍에서 스레드 간 상호작용을 정의
여러 스레드들의 작업 순서를 보장하는 happens-before 관계
자바 메모리 모델에서 스레드 간의 순서 작업을 정의 A 작업에서의 모든 메모리 변경 사항은 B 작업에서 볼 수 있다. 즉, A 작업에서 변경된 내용은 B 작업이 시작되기 전에 모두 메모리에 반영된다.