목록전체 글 (199)
개발 기록
## 프로그램의 동작을 스레드 스케줄러에 기대지 말라 ### 운영체제마다 스레드 스케줄러 정책이 다를 수 있다.- 정확성이나 성능이 스레드 스케줄러에 따라 달라지는 프로그램이라면 다른 플랫폼에 이식하기 어렵다. ### 견고하고 이식성 좋은 프로그램 작성실행 가능한 스레드의 평균적인 수를 프로세서 수보다 지나치게 많아지지 않도록 하는 것실행 가능한 스레드가 CPU 코어 수를 크게 초과하면?스케줄러가 계속 스레드를 교체(컨텍스트 스위칭) 해야 함 (비용 큼)결과: 성능 저하, 응답 지연실행 준비가 된 스레드들은 맡은 작업을 완료할때까지 계속 실행되도록 만들자.괜히 양보(yield)하거나 인위적으로 멈추지 말고, 맡은 일을 끝낼 때까지 실행되도록 설계스레드는 당장 처리해야 할 작업이 없다면 실행돼서는 안 된다..
## 지연 초기화는 신중히 사용하라 ### 지연 초기화 : 필드의 초기화 시점을 그 값이 처음 필요할 때까지 늦추는 기법- 값이 전혀 쓰이지 않으면 초기화도 일어나지 않는다.- 정적 필드, 인스턴스 필드 모두 사용 가능.- 주로 최적화 용도로 쓰이지만, 클래스와 인스턴스 초기화 때 발생하는 위험한 순환 문제를 해결하는 효과도 있다. ### 지연 초기화는 필요할때까지는 하지 말라- 클래스, 인스턴스 생성 시의 초기화 비용은 줄지만 그 대신 지연 초기화하는 필드에 접근하는 비용은 커진다.- 결국 초기화 비율, 비용, 호출 빈도에 따라 실제로는 성능을 느려지게 할 수도 있다. ### 지연 초기화 방식1. 인스턴스 필드의 지연 초기화 - synchronized 접근자 방식private FieldType fiel..

## 스레드 안정성 수준을 문서화하라 한 메서드를 여러 스레드가 동시에 호출할 때 그 메서드가 어떻게 동작하느냐는 해당 클래스와 이를 사용하는 클라이언트 사이의 중요한 계약과 같다. API문서 에서 아무런 언급도 없으면 그 클래스 사용자는 나름의 가정을 해야만 한다. 만약 그 가정 이 틀리면 오류로 이어질 수 있다. ### API 문서에 synchronized 한정자synchronized 한정자가 달려있는 메서드는 스레드 안전하다고 생각할 수 있다. 하지만 이는 몇 가지면에서 틀렸다.메서드 선언에 synchronized 한정자를 선언할지는 구현 이슈일 뿐 API에 속하지 않는다.따라서 이것만으로는 해당 메서드가 스레드 안전하다고 믿기 어렵다.멀티스레드 환경에서도 API를 안전하게 사용하려면 클래스가 지원..
## 과도한 동기화는 피하라 - 과도한 동기화는 성능을 떨어뜨리고, 교착상태에 빠뜨리고, 예측할 수 없는 동작을 낳는다. ### 동기화 메서드나 블록 안에서는 제어를 절대로 클라이언트에 양도하면 안 된다.- 동기화된 영역을 포함한 클래스 관점에서는 재정의할 수 있는 메서드, 클라이언트가 넘겨준 함수 객체는 모두 바깐 세상에서 온 외계인.- 그 메서드가 무슨 일을 할지 알지 못하며 통제할 수도 없는 뜻. ### 해결 방법 : 외계인 메서드 호출을 등기화 블록 바깥으로 옮기기1. 복사해서 락 없이 순회List snapshot;synchronized(observers) { snapshot = new ArrayList(observers); // 🔄 복사}for (Observer o : snapshot) ..
## 스레드보다는 실행자, 태스크, 스트림을 애용해라 ### 실행자 프레임워크 Executor Frameworkjava.util.concurrent 패키지가 등장했다. 이 패키지는 실행자 프레임워크(Executor Framework)라고 하는 인터페이스 기반의 유연한 태스크 실행 기능을 담고 있다. ExecutorService exec = Executors.newSingleThreadExecutor(); // 작업 큐 생성exec.execute(runnable) // 이 실행자에 실행할 task를 넘김exec.shutdown(); // 실행자를 종료실행자 서비스의 다양한 기능특정 태스크가 완료되기를 기다린다.태스크 모음 중 아무것 하나(invokeAny 메서드) 혹은 모든 태스크(invoke..
## 공유 중인 가변 데이터는 동기화해 사용하라 ### synchronized- 해당 메서드나 블록을 한번에 한 스레드씩 수행하도록 보장한다.- 동기화를 잘 하면 객체가 깨진 상태를 읽는 일이 없다. ### 동기화의 중요한 기능- 동기화는 일관성이 깨진 상태를 볼 수 없게 하는 것은 물론,- 동기화된 메서드나 블록에 들어간 스레드가 같은 락의 보호하에 수행된 모든 이전 수정의 최종 결과를 보게해준다. - 스레드가 만든 변화를 다른 스레드에서 확인하게 해준다. ### 원자적 데이터- 언어 명세상 long 과 double 외의 변수를 읽고 쓰는 동작은 원자적이다.- 여러 스레드가 같은 변수를 동기화 없이 수정하는 중이라도, 항상 어떤 스레드가 정상적으로 저장한 값을 온전히 읽어옴을 보장.- int, boo..
## 예외를 무시하지 말라 ### 예외를 명시하는 까닭- 메서드를 사용할때 적절한 조치를 취해달라고 말하는 것.// catch 블록을 비워두면 예외가 무시된다. 아주 의심스러운 코드다!try {} catch (SomeException e) {} - catch 블록을 비워두면 예외가 존재할 이유가 없어진다. ### 예외를 무시해야할때- ex) Fileinputstream을 닫을 때(입력 전용 스트림이므로) 파일의 상태를 변경하지 않았으니 복구할 것이 없으며, (스트림을 닫는다는 건) 필요한 정보는 이미 다 읽었다는 뜻이니 남은 작업을 중단할 이유도 없다. - 예외를 무시하기로 했다면 catch 블록 안에 그렇게 결정한 이유를 주석으로 남기고 예외 변수의 이름도 ignored로 바꿔놓도록 하자. Future..
## 메서드가 던지는 모든 예외를 문서화하라 메서드가 던지는 예외는 그 메서드를 올바로 사용하는 데 아주 중요한 정보다.따라서 각 메서드가 던지는 예외 하나하나를 문서화하는 데 충분한 시간을 쏟아야 한다 ### 검사 예외는 항상 따로따로 선언하고, 각 예외가 발생하는 상황을 자바독의 @throws 태그를 사용하여 정확히 문서화하자.공통 상위 클래스 하나로 뭉뚱그려 선언하는 일은 삼가자.극단적인 예로 메서드가 Exception이나 Throwable을 던진다고 선언해서는 안 된다.메서드 사용자에게 각 예외에 대처할 수 있는 힌트를 주지 못할뿐더러, 같은 맥락에서 발생할 여지가 있는 다른 예외들까지삼켜버릴 수 있어 API 사용성을 크게 떨어뜨린다. ### 자바 언어가 요구하는 것은 아니지만 비검사 예외도 검사..