본문 바로가기
백엔드/Java

Effective Java 맛보기 10탄

by david100gom 2019. 9. 21.

동시성

  1. 공유중인 가변 데이터는 동기화해 사용하라

    • 여러 스레드가 가변 데이터를 공유한다면 그 데이터를 읽고 쓰는 동작은 반드시 동기화 해야 한다. 동기화하지 않으면 한 스레드가 수행한 변경을 다른 스레드가 보지 못할 수도 있다. 공유되는 가변 데이터를 동기화하는 데 실패하면 응답 불가 상태에 빠지거나 안전 실패로 이어질 수 있다. 이는 디버깅 난이도가 가장 높은 문제에 속한다. 간헐적이거나 특정 타이밍에만 발생할 수도 있고, VM에 따라 현상이 달라지기도 한다. 베타적 실행은 필요 없고 스레드끼리의 통신만 필요하다면 volatile한정자만으로 동기화할 수 있다. 다만 올바로 사용하기가 까다롭다. 

  2. 과동한 동기화는 피하라

    • 교착상태와 데이터 훼손을 피하려면 동기화 영역 안에서 외계인 메서드를 절대 호출하지 말자. 일반화해 이야기하면, 동기화 영역 안에서의 작업은 최소한으로 줄이자. 가변클래스를 설계할 때는 스스로 동기화해야 할지 고민하자. 멀티코어 세상인 지금은 과도한 동기화를 피하는 게 과거 어느 때보다 중요하다. 합당한 이유가 있을 때만 내부에서 동기화하고, 동기화했는지 여부를 문서에 명확히 밝히자. 

  3. 스레드보다는 실해자, 태스크, 스트림을 애용하라

  4. wait와 notify보다는 동시성 유틸리티를 애용하라

    • wait와 notify를 직접 사용하는 것을 동시정 '어셈블리 언어'로 프로그래밍하는 것에 비유할 수 있다. 반면 java.util.concurrent는 고수준언어에 비용할 수 있다. 코드를 새로 작성한다면 wait와 notify를 쓸 이유가 거의(어쩌면 전혀)없다. 이들을 사용하는 레거시 코드를 유지보수해야 한다면 wait는 항상 표준 관용구에 따라 while문 안에서 호출하도록 하자. 일반적으로 notify보다는 notifyAll을 사용해야 한다. 혹시라도 nofity를 사용한다면 응당 불가 상태에 빠지지 않도록 각별히 주의하자.

  5. 스레들 안전성 수준을 문서화하라

    • 모든 클래스가 자신의 스레드 안전성 정보를 명확히 문서화해야 한다. 정확한 언어로 명확히 설명하거나 스레드 안전성 애너테이션을 사용할 수 있다. synchroinzed 한정자는 문서화와 관련이 없다. 주건부 스레드 안전 클래스는 메서드를 어떤 순서로 호출할 때 외부 동기화가 요구되고, 그때 어떤 락을 얻어야 하는지도 알려줘야 한다. 무조건적 스레드 안전 클래스를 작성할 때는 synchronized메서드가 아닌 비공개 락 객체를 사용하자. 이렇게 해야 클라이언트나 하위 클래스에서 동기화 매커니즘을 깨트리는 걸 예방할 수 있고, 필요하다면 다음에 더 정교한 동시성을 제어 메커니즘으로 재구현할 여지가 생긴다.

  6. 지연 초기화는 신중히 사용하라

    • 대부분의 필드는 지연시키지 말고 곧바로 초기화해야 한다. 성능 때문에 혹은 위험한 초기화 순환을 막기 위해 꼭 지연 초기화를 서야 한다면 올바른 지연 초기화 기법을 사용하자. 인스턴스 필드에는 이중검사 관용구를, 정적 필드에는 지연 초기화 홀더 클래스 관용구를 사용하자. 반복해 초기화해도 괜찮은 인스턴스 필드에는 단일검사 관용구도 고려 대상이다.

  7. 프로그램의 동작을 스레드 스케줄러에 기대지 말라

    • 프로그램의 동작을 스레드 스케줄러에 기대지 말라. 견고성과 이식성을 모두 해치는 행위다. 같은 이유로, Thread.yield와 스레드 우선순위에 의존해서도 안 된다. 이 기능들은 스레드 스케줄러에 제공하는 힌트일 뿐이다. 스레드 우선순위는 이미 잘 동작하는 프로그램의 서비스 품질을 높이기 위해 드물게 쓰일 수는 있지만, 간신히 동작하는 프로그램을 '고치는 용도'로 사용해서는 절대 안된다.

 

참조서적 및 페이지 : 이펙티브 자바 Effective Java 3/E (http://www.yes24.com/Product/Goods/65551284)

댓글