메모리 가시성 문제
는 멀티스레드 환경에서 한 스레드가 변경한 변수의 값이 다른 스레드에게 즉시 또는 올바르게 보이지 않는 상황을 말합니다.
A Thread
에서 공유되는 자원인 value
의 값을 변경하였고, 이후 B Thread
에서 접근하여 확인하는데, 변경값이 적용이 안되어있는 현상을 얘기합니다.데이터 정합성
문제가 발생 할 듯 합니다.
Java
에서는 각 스레드의 성능 향상을 위해, 자주 사용하는 변수는CPU 캐시
에 저장 하게 됩니다.
Thread A
, Thread B
가 각자 같은 변수를 읽어 오거나, 값을 변경 시키더라도, 자신만 사용하는 CPU 캐시에 이 값을 저장해두고 사용하게 되는 겁니다.실제 코드와 결과를 통해 알아 보겠습니다.
package memory;
public class TestMain {
public static void main(String[] args) {
PlusThread plusThreadA = new PlusThread();
Thread threadA = new Thread(plusThreadA, "ThreadA");
threadA.start();
System.out.println(Thread.currentThread().getName() + " is start!!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//실행 Flag false처리 후, 값 변경 되었는지 확인.
plusThreadA.runFlag = false;
System.out.println("plusThreadA.isRunFlag() = " + plusThreadA.isRunFlag());
System.out.println(Thread.currentThread().getName() + " is End!!");
}
private static class PlusThread implements Runnable {
boolean runFlag = true;
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "시작");
while (runFlag){
// System.out.println(Thread.currentThread().getName() + "동작 중");
}
System.out.println(Thread.currentThread().getName() + "종료");
}
public boolean isRunFlag() {
return runFlag;
}
}
}
true
) 계속 Thread를 유지하고 있는 상태입니다.main Thread
에서 ThreadA
의 runFlag
를 false로 바꿨을 때, while문의 조건이 false
가 되며 종료가 되어야 한다.main is start!!
ThreadA시작
plusThreadA.isRunFlag() = false
main is End!!
ThreadB종료
하지만 실제 동작은, ThreadA
가 종료되지 않고 무한 대기 실행 상태에 빠지게 된다.
메모리가시성
문제가 발생되어 그렇다.runFlag
는 메인 메모리
에 있는 인스턴스의 runFlag
가 아닌, CPU의 캐시에 저장된 runFlag
값을 사용해서 진행하게 된다.CPU메모리
(runFlag
)는 메인메모리
의 runFlag = true
값이 아직 반영되지 않은 것이다.CPU 캐시
를 사용하지 않고, 메인 메모리
만을 사용하여 값을 가져오고, 저장하게 된다.~~
private static class PlusThread implements Runnable {
volatile boolean runFlag = true;
~~
ThreadA시작
main is start!!
ThreadA종료
plusThreadA.isRunFlag() = false
main is End!!
volatile
키워드를 사용한 변수는, CPU 캐시
를 사용하지 않고, 메인 메모리
만을 사용하여 값을 사용하기에 성능적으로 확실하게 느려진다.진행 할 수도 있다
이다. 동기화를 할 수도 안할 수도 있기때문에 volatile
을 대신해서 이런 기법을 사용한다면 보장되지 않는 멀티스레드 환경을 구축하는 것이다.