핵심 내용 모든 클래스를 자신의 스레드 안전성 정보를 명확히 문서화해야 한다. 정확한 언어로 명확히 설명하거나 스레드 안전성 애너테이션을 사용할 수 있다. synchronized 한정자는 문서화와 관련이 없다. 조건부 스레드 안전 클래스는 메소드를 어떤 순서로 호출할 때 외부 동기화가 요구되고, 그때 어떤 락을 얻어야 하는지도 알려줘야 한다. 무조건적 스레드 안전 클래스를 작성할 때는 synchronized 메소드가 아닌 비공개 락 객체를 사용하자. 클라이언트나 하위 클래스에서 동기화 메커니즘을 깨뜨리는 걸 예방할 수 있다. API 문서에서 synchronized 한정자 : synchronized 한정자만으로 스레드 안전성을 판단하는 것은 위험하다. 메소드의 내부 구현이나 호출하는 다른 메소드들과의 상호..
핵심 요약 당연히 wait와 notify가 아닌 동시성 유틸리티를 사용하라. 레거시 코드를 다룰 경우, wait는 항상 표준 관용구에 따라 while 문 안에서 호출하라. 일반적으로 notify보다는 notifyAll을 사용해야 한다. notify을 사용할 경우 응답 불가 상태에 빠지지 않도록 주의하자. 동시성 유틸리티 : 자바 5 이후 wait와 notify로 하드코딩해야 했던 전형적인 일들을 대신 해준다. java.util.concurrent의 고수준 유틸리티는 세 범주로 나눌 수 있다. 1. 실행자 프레임워크(item 80) 2. 동시성 컬렉션(concurrent collection) 3. 동기화 장치(synchronizer) 동시성 컬렉션(concurrent collection) 표준 컬렉션 인터..
핵심 내용 스레드를 직접 다루는 대신 실행자 프레임워크와 태스크를 활용하고, 병렬 처리는 스트림을 통해 진행하자. 이렇게 하면 작업과 실행 메커니즘이 분리되며, 실행자는 태스크의 수행 정책을 선택하게 해주며, 병렬 처리를 효과적으로 수행할 수 있다. java.util.concurrent 패키지 : 실행자 프레임워크(Executor Framework) 해당 패키지가 나오기 이전에는 작업 큐를 사용하려면 안전 실패나 응답 불가능한 문제를 해결하기 위한 코드를 추가해야 했다. java.util.concurrent 패키지가 등장하면서 실행자 프레임워크(Executor Framework)를 제공한다. // 작업 큐를 생성하다. (ExecutorService는 실행자 서비스를 나타내는 인터페이스) ExcutorSe..
핵심 요약 교착 상태와 데이터 훼손을 피하려면 동기화 영역 안에서 외계인 메소드를 절대 호출하지 말자. 동기화 영역 안에서의 작업은 최소한으로 줄이자. 가변 클래스를 설계할 때는 스레드 안전한 클래스를 만들지에 대한 여부를 고민하자. 그리고 이를 문서에 명기하자. 과도한 동기화 동기화는 프로그램 안정성을 보장하기 위해 중요하지만, 과도하게 사용하면 성능 저하, 교착 상태, 예측할 수 없는 동작 등의 문제를 야기할 수 있다. 동기화된 영역에서는 클라이언트에게 제어를 양도하면 안 된다. 예를 들어, 재정의할 수 있는 메소드 호출이나 클라이언트가 전달한 함수 객체 호출은 동기화된 영역에서 예측 불가능한 문제를 발생시킬 수 있다. ❔ 외계인 메소드 더보기 외계인 메서드란 동기화된 영역 안에서 재정의 메서드를 호..
핵심 요약 멀리 스레드 환경에서 가변 데이터를 공유할 때는 데이터의 일관성과 안정성을 위해 동기화를 사용하라. 데이터를 동기화하지 않으면 에측할 수 없는 결과나 안전 실패(safe failure)가 발생할 수 있다. 최적의 성능과 안정성을 위해 가변 데이터는 가능한 한 단일 스레드 내에서만 사용하거나, 필요한 부분만 동기화하라. 동기화의 기능 배타적 실행 (Exclusive Execution) synchronized 키워드는 해당 메소드나 블록을 한 번에 하나의 스레드만 실행할 수 있도록 보장한다. 동기화된 메소드를 사용하면, 한 스레드가 객체의 상태를 변경하는 도중에 다른 스레드가 해당 객체의 상태를 읽거나 변경하는 것을 방지할 수 있다. 즉, 동기화를 통해 객체의 상태가 항상 일관된 상태를 유지하도록..
이번 절의 내용은 검사와 비검사 예외에 똑같이 적용된다. ✍ catch 블록을 비워두지 말자. 메소드에서 발생하는 예외를 무시하면, 그 메소드가 의도한대로 동작하지 않을 수 있고, 이로 인한 잠재적인 문제가 발생할 수 있다. 예시 1 - FileInputStream close 메소드 : 예외를 무시해도 되는 경우 FileInputStream은 파일에서 데이터를 읽기 위한 입력 전용 스트림이다. 즉, 파일의 상태를 변경시키지 않는다. 따라서 이 스트림을 닫는 도중 예외가 발생해도 파일에 대한 복구 작업은 필요하지 않다. @Slf4j public class Main { public void readFile() { File file = new File("a.txt"); try (FileInputStream f..
핵심 요약 실패 원자성은 메소드 호출이 실패하더라도 해당 객체의 상태를 변경하지 않아야 함을 나타낸다. 실패 원자성을 달성하기 위해 불변 객체 사용, 유효성 검사, 임시 구조 사용, 복구 코드 사용 등을 이용하자. 실패 원자성을 항상 보장하기는 어렵지만, 그렇지 않을 경우 API 문서에 명시해야 한다. 실패 원자성(Failure Atomicity) ✍ 호출된 메소드가 실패하더라도 해당 객체는 메소드 호출 전 상태를 유지해야 한다. 위와 같은 특성을 실패 원자성이라고 한다. 실패 원자성은 시스템의 안정성, 성능, 신뢰성을 향상시키는 데 필수적이다. 메소드를 실패 원자적으로 만드는 방법 방법 1 | 불변 객체 사용 : 불변 객체로 설계한다. (item 17) 불변 객체는 생성 이후 절대 변하지 않으므로 자연..
핵심 요약 스택 추적은 예외 발생 시점의 메소두 호출 정보를 제공하여 디버깅을 돕는다. 예외 메시지에는 관련 매개변수와 필드 정보를 포함하여 구체적인 실패 원인을 알 수 있게 해야 한다. 예외 클래스를 확장하고, 필요한 상세 정보를 얻기 위한 접근자 메소드를 제공하는 것이 좋다. 스택 추적(Stack Trace) 프로그램이 실행되면서 메소드 호출이 일어날 때마다 해당 메소드의 정보가 스택에 쌓인다. 이때, 프로그램에서 예외가 발생하면 그 시점의 호출 스택을 표시하는 정보를 "스택 추적"이라고 한다. ex. 예외가 발생한 순간의 메소드 호출 순서, 위치 정보, 관련 파일명 등 예외가 발생하고 해당 예외를 잡아내지 못하면, JVM은 그 예외의 스택 추적 정보를 자동으로 콘솔에 출력한다. 예외 객체의 toSt..