java.util.concurrent 아이템 49에서 백그라운드 스레드에 위임해 비동기적으로 작업을 요청해 처리하는 작업 큐를 생성해 사용했었다. 이제는 직접 사용자가 작업 큐를 작성하지 않고 java.util.concurrent 패키지를 사용하면 된다. 실행자 프레임워크라고 하는 인터페이스 기반의 유연한 태스크 실행 기능을 담고 있다. ExecutorService exec = Executors.newSingleThreadExecutor(); //실행자 생성 exec.execute(runnable); //실행 할 태스크를 넘기는 방법 exec.shutdown(); //실행자를 종료시키는 방법 ExecutorService(실행자 서비스)의 주요 기능들 큐에 작업을 제출하고서 작업이 완료될 때까지 기다릴 수..
과도한 동기화 과도한 동기화는 성능 저하, 교착상태, 예측할 수 없는 동작을 야기한다. 응답 불가와 안전 실패를 피하려면 동기화 메서드나 동기화 블록 안에서는 제어를 절대로 클라이언트에게 양도하면 안됨 예를 들어, 동기화된 영역 안에서는 재정의할 수 있는 메서드를 호출하거나 클라이언트가 넘겨준 함수 객체 [아이템 24]를 호출해서도 안됨 이런 외계인 메서드에서는 무엇을 할 지 알지 못하고 통제할 수도 없음 과도한 동기화 예제 Observer Pattern 으로 구현한 Set Observer Pattern : 객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴이다. 클라이언트는..
synchronized 키워드 해당 메서드나 블록을 한번에 한 스레드씩 수행하도록 보장 동기화의 기능 1) 배타적 실행 한 스레드가 변경하는 중이라서 상태가 일관되지 않을 때 객체를 다른 스레드가 보지 못하게 막는 것 객체를 하나의 일관된 상태에서 다른 일관된 상태로 변화 : 한 객체가 일관된 상태를 가지고 생성 → 객체에 접근하는 메서드는 그 객체에 락(lock)을 걸음 → 락을 건 메서드는 필요하면 객체를 수정 2) 스레드 사이 안정적인 통신 동기화 없이는 한 스레드가 만든 변화를 다른 스레드에서 확인하지 못할 수 있다. 변경된 데이터의 최종 결과 값을 읽을 수 있게 한다. 원자적 (atomic) 자바에서 long / double 외 변수를 읽고 쓰는 동작은 원자적이다. (동기화 없이도 항상 어떤 스..
예외 처리란, 예외 상황에 적절한 처리를 하기 위해 존재 → 무시하지 말자. catch 블록 비워두기 try { // ... } catch(Exception e) { // catch 블록을 비워두면 예외가 무시된다. } 예외를 무시해야할 때 예를 들어 읽기전용 스트림인 FileInputStream을 닫을 때 예외가 발생하면 어떤 조치를 해줄 필요가 없다. 이런 경우에 catch 문안에 주석으로 이유를 남기고 예외 변수의 이름도 ignored로 바꿔놓는다. Future f = exec.submit(planarMap::chromaticNumber); int numColors = 4; // 기본값 try { numColors = f.get(1L, TimeUnit.SECONDS); } catch(TimeoutE..
실패 원자적(failure-atomic) 예외가 발생해도 여전히 정상적으로 사용할 수 있는 상태라면 얼마나 좋을까? 호출된 메서드가 실패하더라도 해당 객체는 호출 전 상태를 유지해야한다. 실패 원자적인 메서드 만드는 방법 1) 불변 객체 [아이템 17]로 설계하기 불변 객체는 태생적으로 실패 원자적 불변 객체의 상태는 생성 시점에 고정되어 절대 변하지 않기 때문에 메서드가 실패해도 불안정한 상태에 빠지지 않는다. 2) 가변 객체의 메서드의 경우 작업 수행 전 매개변수의 유효성을 검사하기 [아이템 49] 객체의 내부 상태를 변경하기 전에 잠재적 예외 가능성 대부분을 걸러낼 수 있는 방법 public Object pop() { if (size == 0) //매개변수의 유효성 검사 throw new Empty..
예외 상세 메세지 예외를 잡지 못해 프로그램이 실패하면 자바 시스템은 그 예외의 스택 추적 정보(예외 객체의 toString 메서드를 호출)를 자동으로 출력한다. 그 정보로부터 실패원인을 분석해야하기 때문에 예외의 toString 메서드에 실패 원인에 관한 정보를 가능한 많이 담아 반환해야한다. 발생한 예외에 관련된 모든 매개변수,필드 값을 담아야함 → 무엇을 고쳐야 할지 분석하는 데 도움이 됨 장황할 필요는 없고, 예외 원인을 파악하기 쉬운 메세지가 좋다. public IndexOutOfBoundsException(int lowerBound, int upperBound, int index) { super(String.format( "최솟값: %d, 최댓값: %d, 인덱스: %d", lowerBound,..
예외 문서화 메서드가 던지는 예외는 그 메서드를 올바르게 사용하기 위한 중요한 정보이므로 예외 하나하나를 문서화하는 데 충분한 시간을 쏟아야한다. [아이템 56] 검사 예외는 항상 따로따로 선언하고, 각 예외가 발생하는 상황을 자바독의 @throws 태그를 사용하여 정확히 문서화하자. 공통 상위 클래스 하나로 예외를 던지는 것을 삼가자. ex)Exception, Throwable (main 메서드만 예외) 비검사 예외도 검사 예외처럼 정성껏 문서화해두면 좋음 → 그 메서드를 성공적으로 수행하기 위한 전제조건이 됨 메서드가 던질 수 있는 예외를 @throws 로 문서화하되, 비검사 예외는 메서드 선언의 throws 목록에 넣지 말자. (검사냐 비검사냐에 따라 API 사용자가 할 일이 달라지므로 확실히 구분..
메서드가 저수준 예외를 처리하지 않고 바깥으로 전파했을 때 수행하려는 일과 관련 없어 보이는 예외가 발생 내부 구현 방식을 드러내어 윗 레벨 API를 오염 구현 방식을 바꾸면 다른 예외가 발생하여 기존 클라이언트 프로그램을 깨지게함 예외 번역 (exception translation) 위 문제를 피하기 위해선 상위 계층에서 저수준 예외를 잡아 자신의 추상화 수준에 맞는 예외로 바꿔 던져야함 (예외 번역) try { // 저수준 추상화를 이용 } catch (LowerLevelException e) { // 추상화 수준에 맞게 번역 throw new HigherLevelException("exception"); } // AbstractSequentialList에서 수행하는 예외번역 예시 public abs..