이펙티브 자바
아이템 78. 공유중인 가변 데이터는 동기화 해서 사용하라.
동기화(synchronized)는 배타적 실행뿐 아니라 스레드 사이에 안정적인 통신에도 필요하다.
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
| package com.github.sejoung.codetest.concurrent.brokenstopthread;
import java.util.concurrent.TimeUnit;
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> { int i = 0; while(!stopRequested){ i++; } }).start();
TimeUnit.SECONDS.sleep(1); stopRequested = true; } }
|
위에 동작은 1초내에 종료할것이라고 생각이 되는가? vm에서 hoisting이 일어나서 종료되지 않는다.
1 2 3 4
| while(!stopRequested){ i++; }
|
위에 코드가 아래 코드 처럼 최적화 되는것을 말한다.
1 2 3 4 5 6 7
| if(!stopRequested){ while(true){ i++; } }
|
그러면 코드를 수정해 보면
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 31 32 33 34
| package com.github.sejoung.codetest.concurrent.fixedstopthread1;
import java.util.concurrent.TimeUnit;
public class StopThread {
private static boolean stopRequested;
private static synchronized void requestStop() { stopRequested = true; }
private static synchronized boolean stopRequested() { return stopRequested; }
public static void main(String[] args) throws InterruptedException { Thread backgroundThread = new Thread(() -> { int i = 0; while (!stopRequested()) { i++; } }); backgroundThread.start();
TimeUnit.SECONDS.sleep(1); requestStop(); } }
|
위처럼 동기화 synchronized를 선언하거나
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.github.sejoung.codetest.concurrent.fixedstopthread2;
import java.util.concurrent.TimeUnit;
public class StopThread {
private static volatile boolean stopRequested;
public static void main(String[] args) throws InterruptedException { new Thread(() -> { int i = 0; while (!stopRequested) { i++; } }).start();
TimeUnit.SECONDS.sleep(1); stopRequested = true; } }
|
위에 코드 처럼 volatile으로 선언하여 처리하는 것이다 volatile 키워드는 모든것을 해결해주지 않는다.
가변 데이터는 단일 쓰레드에서만 사용하자.
참조