Skip to content

ㄴ 11장 동시성

yongfucius edited this page Jun 17, 2019 · 1 revision

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

동기화할 때는 쓰기와 읽기 모두가 동기화되어야 한다.
volatile은 배타적 수행과는 상관없고 가장 최근에 기록된 값을 읽게 한다.
java.util.concurrent.atomic 패키지의 클래스처럼 lock-free하면서도 thread-safe한 클래스를 사용하자.

그냥 가변 데이터는 단일 쓰레드에서만 써.


아이템 79 과도한 동기화는 피하라

동기화 영역 안에서는 외계인 메서드는 절대 금지. 동기화 영역 안에서의 작업을 최대한 줄여라.
가변 클래스에서는 클라이언트에서 알아서 동기화하게 할지, 아니면 thread-safe하게 만들지 고민하자(lock splitting? lock striping? nonblocking concurrency control?).

멀티코어 세상인 지금 과도한 동기화를 피하는 게 어느 때보다 중요하다.


아이템 80 스레드보다는 실행자(Executor), 태스크(Task), 스트림(Stream)을 애용하라

자바 병렬 프로그래밍(에이콘 출판사, 2008) 참조


아이템 81 wait와 notify보다는 동시성 유틸리티를 애용하라

동시성 수준만큼의 스레드를 생성못하는 경우도 생길 수 있는데 이런 경우를 스레드 기아 교착상태 thread starvation deadlock.
InterruptedException을 캐치하면 Thread.currentThread().interrupt() 관용구를 사용해 인터럽트(interrupt)를 되살린다.
시간 간격을 잴때는 항상 System.nanoTime

wait와 notify는 쓰지마.


아이템 82 스레드 안전성 수준을 문서화하라

  • 불변 immutable
  • 무조건적 스레드 안전 unconditionally thread-safe: 내부에서 충실히 동기화해서 외부 동기화 불필요
  • 조건부 스레드 안전 conditionally thread-safe: 일부 메서드는 외부 동기화 필요
  • 스레드 안전하지 않음 not thread-safe: 동시에 사용하려면 외부 동기화 필수
  • 스레드 적대적 thread-hostile: 정적 데이터를 아무 동기화없이 수정하는 경우(외부 동기화도 답이 없는 상태)

thread-safe하려면 `synchronized` 메서드가 아닌 비공개 락 객체를 사용하자.

아이템 83 지연 초기화는 신중히 사용하라

지연 초기화(lazy initialization)이 필요한 경우는 사용 비율이 낮은데 초기화 비용이 큰 경우이다. 하지만 정말 그런지 확인하는 방법이 성능을 측정해보는 방법 밖에 없다. **대부분의 상황에서는 일반적인 초기화가 지연 초기화보다 낫다. **
정적 필드를 지연 초기화해야 한다면 지연 초기화 홀더 클래스(lazy initialization holder class) 관용구.
인스턴스 필드를 지연 초기화해야 한다면 이중검사(double-check) 관용구.


아이템 84 프로그램의 동작을 스레드 스케줄러에 기대지 말라

스레드의 평균적인 수를 프로세서 수보다 지나치게 많아지지 않도록 하자.
스레드는 절대 바쁜 대기(busy waiting) 상태가 되면 안된다.