본문 바로가기

책정리/EfectiveJava

(6)
지연 초기화는 신중히 사용하라 지연 초기화(Lazy initialization) - 필드의 초기화 시점을 늦춰 처음 필요로 할 때 값을 초기화 - 값이 쓰이지 않으면 초기화도 일어나지 않음 지연 초기화는 양날의검이다. - 클래스 혹은 인스턴스 생성 시 초기화 비용은 줄지만 지연 초기화하는 필드에 접근하는 비용이 커짐 지연 초기화 성능을 느려지게 하는 요소 1. 초기화가 이뤄지는 필드에 비율 2. 실제 초기화에 드는 비용 3. 초기화된 필드를 얼마나 빈번히 호출 하느냐에 따라 지연 초기화가 필요할 때 1 . 클래스의 인스턴스 중 그 필드를 사용하는 인스턴스의 비율이 낮음 2. 필드를 초기화하는 비용이 큼 정말 그런지 유일하게 알 수 있는 방법은 지연 초기화 적용 전후의 성능을 측정 해봐야 함 멀티 스레드 환경에서는 지연 초기화 하기가 ..
스레드 안전성 수준을 문서화 하라 API문서에 synchronized키워드가 있는 메서드는 스레드 안전하다고 할 수 있다. 하지만 이 말은 몇가지 틀린 이야기 일 수 도 있다. 멀티 스레드 환경에서도 API를 안전하게 사용하려면 클래스가 지원하는 스레드 안전성 수준을 정확히 명시해야함 다음은 스레드 안전성 수준을 높은 순서대로 나열 불변(imuutable) - 상수와 같아서 외부 동기화도 필요 없음 - String, Long, BigInteger 무조건적 스레드 안전(unconditionally thread-safe) - 수정될 수 있으나 내부에서 충실히 동기화하여 별도의 외부 동기화 없이 동시에 사용해도 안전 - AtomicLong, ConcurrrentHashMap 조건부 스레드 안전(conditionally thread-safe) ..
wait와 notify보다는 동시성 유틸리티를 이용하라 고수준 동시성 유틸리티가 나오기 이전에는 wait과 notify를 하드코딩 해서 사용하였지다 고수준의 동시성 유틸리티가 나오면서 wait과 notify를 사용해야할 이유가 많이 줄었다. 따라서 wait과 notify는 올바르게 사용하기 아주 까다로우니 고수준 동시성 유틸리티를 사용하자 java.util.concurrent의 고수준 유틸리느는 새 범주로 나뉨 1. 실행자 프레임 워크 (이전 장에서 확인) 2. 동시성 컬렉션 (이번에) 3. 동기화 장치 (이번에) 동시성 컬렉션 List, Queue, Map같은 표준 컬렉션 인터페이스에 동시성을 가미해 구현한 고성능 컬렉션 병행성을 높이기 위해 동기화를 내부에서 수행함. 동시성 컬렉션에서 동시성을 무력화 하는건 불가능 외부에서 락을 추가로 사용하면 오히려 속..
스레드보다는 실행자, 태스크, 스트림을 애용하라 초판에서는 작업큐를 설명 했지만 java.util.concurrent 패키지가 등장하므로 다음 한줄로 작업큐를 대체할 수 있게 됨 ExecutorService exec = Executors.newSingleThreadExecutor(); //실행 태스크를 넘기는 방법 exec.execute(runnable); //실행자를 종료시키는 방법 exec.shutdown 실행자 서비스의 주요 기능 특정 태스크가 완료되기를 기다림 (get메서드) 아무것 하나 (invokeAny) 혹은 모든 태스크 (invokeAll)가 완료되기를 기다림 종료하기를 기다림(awaitTermination) 완료된 태스크들의 결과를 차례로 받음 (ExecutorCompletionService) 태스크를 특정 시간에 혹은 주기적으로 실행..
과도한 동기화는 피하라 과도한 동기화는 성능을 떨어뜨리고, 교착상태에 빠뜨리고, 심지어 예측할 수 없는 동작을 낳기도 한다. 응답 불가와 안전 실패를 피하려면 동기화 메서드나 동기화 블록 안에서는 절대로 제어를 클라이언트에 양도하면 안됨 동기화된 영역 안에서는 재정의할수 있는 메서드를 호출하면 안됨 클라이언트가 넘겨준 함수객체를 호출해서도 안됨 동기화된 클래스 관점에서는 이런 메서드는 모두 외계인 메서드다 외계인 메서드는 하는일에 따라 동기화된 영역은 예외를 일으키거나 교착상태에 빠지거나 데이터를 훼손할 수 있다. 외계인 메서드 호출 public class ObservableSet extends ForwardingSet { public ObservableSet(Set set) { super(set); } private fina..
공유 중인 가변 데이터는 동기화해 사용하라 동기화란? 여러 스레드가 한개의 자원을 사용할 때 점유한 스레드를 제외 하고 나머지 스레드들은 접근하지 못하도록 베타적인 락을 통해 보호 기능을 사용하는 것을 말함. (Synchronized) 하지만 자바에서는 volatile변수, 명시적 락, 단일 연산 변수(Atomic variable)을 사용하는 경우에도 '동기화'라는 용어를 사용 함. 동기화는 일관성이 깨진 상태를 볼 수 없게 함 스레가드가 같은 락의 보호하에 수행된 모든 이전 수정의 최종 결과를 보게 해줌 long과 double 외에 변수를 읽고 쓰는 동작은 원자적이다. 그렇다고 해서 성능을 높으려고 읽고 쓸때 동기화를 하지 않으면 아주 위험한 발상 필드를 읽을 때 항상 수정이 완전히 반영된 값을 얻는다고 보장 한 스레드가 저장한 값이 다른 스레..