아이템 78. 공유중인 가변 데이터는 동기화 해서 사용하라.

이펙티브 자바

아이템 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;

// 코드 78-1 잘못된 코드 - 이 프로그램은 얼마나 오래 실행될까? (415쪽)
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;

// 코드 78-2 적절히 동기화해 스레드가 정상 종료한다. (416쪽)
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;

// 코드 78-3 volatile 필드를 사용해 스레드가 정상 종료한다. (417쪽)
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 키워드는 모든것을 해결해주지 않는다.

가변 데이터는 단일 쓰레드에서만 사용하자.

참조