volatile은 멀티스레드에서 값들을 캐시하지않고 변경된 내용을 바로바로 가져올 수 있게 해준다.
오! 그렇다면 아무 곳에나 volatile만 넣어준다면 마법처럼 동기화가 되면서 공유상태를 사용할 수 있는 것일까?
아래 소스코드와 결과를 보면 그렇제 않은 것 같다.
package volatile_test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class VolatileTest1 {
private volatile static int counter = 0;
public static void main(String[] args) {
Runnable r1 = () -> { System.out.println(counter); counter++;};
ExecutorService es = Executors.newCachedThreadPool();
for(int i = 0; i < 10; i++) {
es.execute(r1);
}
es.shutdown();
// OUTPUT
// 0
// 0
// 0
// 3
// 4
// 5
// 6
// 7
// 8
// 9
}
}
0이 3번이나 나왔다. 왜그럴까? 특이한 것은 결과적으로 +1이 잘 되었지만 조회가 잘 안되었다는 것인데 다시 한 번 해보자.
0 0 0 0 0 0 6 6 8 8전혀 다른 값이 나왔다. 그 말은 값이 달라졌다는 것이다. volatile을 사용한다고 동기화가 되는 것이 아니다. 읽기-수정-쓰기 가 동기화가 되야 하는 것이다. 그렇다면 volatile은 언제 써야 할까? 아래와 같은 경우를 보자.
package volatile_test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class VolatileTest2 {
// 아래 내용을 보자. 과연 잘 돌아가는 경우가 얼마나 있을까?
private static boolean flag = true;
public static void main(String[] args) {
Runnable r1 = () -> {
while(flag) {
// 여기에 막히게 된다.
}
System.out.println("bye");
};
Runnable r2 = () -> { System.out.println("flag false start"); flag = false;};
ExecutorService es = Executors.newCachedThreadPool();
for(int i = 0; i < 10; i++) {
es.execute(r1);
}
es.execute(r2);
es.shutdown();
}
}
여기서는 전혀 돌아가지는 않는다.
이것은 volatile의 부재일 수도 있지만, 컴파일러 마다 최적화를 하면서 결과값이 다르게 나올 수도 있다고 한다.
여튼 위 내용은 현재 flag를 false로 변경했지만 먹히지 않는다.
이때 volatile을 넣어보자.
package volatile_test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class VolatileTest3 {
// 이럴때 volatile로 바꾸는 것만으로 효과가 있다.
private volatile static boolean flag = true;
public static void main(String[] args) {
Runnable r1 = () -> {
while(flag) {
// System.out.println("hi");
}
System.out.println("bye");
};
Runnable r2 = () -> { System.out.println("flag false start"); flag = false;};
ExecutorService es = Executors.newCachedThreadPool();
for(int i = 0; i < 10; i++) {
es.execute(r1);
}
es.execute(r2);
es.shutdown();
}
}
댓글 없음:
댓글 쓰기