Item 78 : 공유 중인 가변 데이터는 동기화해 사용하라
2021. 9. 15. 22:50
- synchronized 키워드는 해당 메소드나 블록을 한번에 한 스레드씩 수행하도록 보증한다.
- 동기화는 단순히 배타적 실행을 보증하는 것 뿐만 아니라 동기화된 메소드나 블록에 들어간 스레드가 같은 락의 보호하에 수행된 모든 이전 수정의 최종 결과를 보게 해준다.
- 자바 언어 명세는 스레드가 필드를 읽을 때 항상 '수정이 완전히 반영된' 값을 얻는다고 보장하지만, 한 스레드가 저장한 값이 다른 스레드에게 '보이는가'는 보장하지 않는다.
동기화는 배타적 실행뿐 아니라 스레드 사이의 안정적인 통신에 꼭 필요하다.
- 이는 한 스레드가 만든 변화가 다른 스레드에게 언제 어떻게 보이는지를 규정한 자바의 메모리 모델 때문이다.
- 공유중인 가변 데이터를 비록 원자적으로 읽고 쓸 수 있을지라도 동기화에 실패하면 처참한 결과를 불러온다.
- 다른 스레드를 멈추는 작업을 예시로 보자
- Thread.stop은 안전하지 않아 사용 금지 처리되었다.
- 다음 코드에서 스레드는 boolean 필드를 폴링하면서 그 값이 true가 되면 멈춘다.
- false로 초기화해놓고 다른 스레드에서 이 스레드를 멈추고자 할 때 true로 변환한다는 의미다.
//잘못된 코드
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args)
throw InterruptedExcpetion {
Thread backgroundThread = new Thread(() -> {
int i = 0;
while (!stopRequested)
i++;
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
- 이 스레드는 1초뒤에 종료될 것 같지만 무한루프를 돈다.
- 동기화하지 않으면 메인 스레드가 수정한 값을 백그라운드 스레드가 언제쯤 보게 될지 보증할 수 없다.
// 적절한 동기화
public class StopThread {
private static boolean stopRequested;
private static synchronized boolean requestStop() {
stopRequested = true;
}
private static synchronized boolean stopRequested() {
return stopRequested;
}
public static void main(String[] args)
throw InterruptedExcpetion {
Thread backgroundThread = new Thread(() -> {
int i = 0;
while (!stopRequested())
i++;
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
requestStop();
}
}
- 쓰기 (requestStop)와 읽기(stopRequested) 모두를 동기화 했다.
- 쓰기와 읽기가 모두 동기화 되지 않음녀 동작을 보장하지 못한다.
이 후 책에서는 volatile 한정자를 이용한 방법을 제시하는데 이 부분은 따로 공부를 추가로 한 뒤 포스팅을 하겠다.
- 결과적으로 가변데이터를 공유하지 말고 단일 스레드에서만 사용하는 것이 최고다.
정리
- 여러 스레드가 가변 데이터를 공유한다면 그 데이터를 읽고 쓰는 동작은 반드시 동기화 해야한다.
- 배타적 실행은 필요 없고 스레드끼리의 통신만 필요하다면 volatile 한정자만으로 동기화 할 수 있지만 까다롭다.
'책 > 이펙티브자바' 카테고리의 다른 글
Item 80 : 스레드보다는 실행자, 태스크, 스트림을 애용하라. (0) | 2021.09.17 |
---|---|
Item 79 : 과도한 동기화는 피하라 (0) | 2021.09.16 |
Item 77 : 예외를 무시하지 말라 (0) | 2021.09.13 |
Item 76 : 가능한 한 실패 원자적으로 만들라 (0) | 2021.09.12 |
Item 75 : 예외의 상세 메시지에 실패 관련 정보를 담으라 (0) | 2021.09.11 |