동기화는 베타적 실행뿐 아니라 스레드 사이의 안정적인 통신에 있어서 꼭 필요하다.
여러 쓰레드가 가변데이터를 공유하고 있다면 그 데이터를 읽고 쓰는 동작은 반드시 동기화 해야 한다.
쓰기와 읽기 모두가 동기화하지 않으면 동기화가 보장되지 않는다.
응답 불가와 안전 실패를 피하려면 동기화 메소드나 동기화 블록 안에서는 제어를 절대로 클라이언트에 양도해선 안된다.
기본 규칙은 동기화 영역에서는 가능한 한 일을 적게 하는것이 좋다.
합당한 이유가 있는 경우에만 내부에서 동기화를 하고, 동기화를 했는지 여부를 문서로 명확하게 밝히자 (아이템 82)
Executor 서비스의 주요 기능
특정 task가 완료되기를 기다린다.
task 모음 중 아무것 하나 (invokeAny 메소드) 혹은 모든 task(invokeAll 메소드)가 완료 되길 기다린다.
실행자 서비스가 종료 하기를 기다린다.(awaitTermination 메소드)
완료된 task들의 결과를 차례대로 받는다 (ExecutorCompletionService)
task를 특정 시간에 혹은 주기적으로 실행하게 된다 (ScheduledThreadPoolExecutor 이용)
wait과 notifiy는 올바르게 사용하기가 까다로우니 고수준 동시성 유틸리티를 사용하자
java.util.concurrent의 고수준 유틸리티는 세 범주로 나눌 수 있다.
실행자 프레임워크
동시성 컬랙션 : List, Queue, Map과 같은 표준 컬렉션 인터페이스에 동시성을 가미해 구현한 고성능 컬렉션이다.
: 동시성 컬랙션에서 동시성을 무력화하는것은 불가능 하며, 외부에서 락을 추가로 사용하면 오히려 속도가 느려진다.
동기화 장치
ConcurrentHashMap
시간을 잴땐 System.currentTimeMillis 가 아닌 System.namoTime을 사용하자
wait 메소드를 사용하게 되는 경우는 반드시 대기 반복문(wait loop) 관용구를 사용하라. 반복문 밖에서는 절대로 호출하지 말자.
메소드 선언에 synchronized 한정자를 선언할지는 구현이슈일 뿐 API에 속하지 않는다.
멀티스레드 환경에서도 API를 안전하게 사용하려면 클래스가 지원하는 스레드 안전성 수준을 정확히 명시해야 한다.
지연 초기화는 필드의 초기화 시점을 그 값이 처음 필요할떄까지 늦추는 기법이다.
지연 초기화가 초기화 순환성을 깨트릴 것 같으면 synchronized를 단 접근자를 사용하자.
성능 때문에 정적 필드를 지연 초기화해야 한다면 지연 초기화 홀더 클래스 관용구를 사용하자.
성능 때문에 인스턴스 필드를 지연 초기화해야 한다면 이중검사 관용구를 사용하자.
정확성이나 성능이 스레드 스케줄러에 따라 달라지는 프로그램이라면 다른 플랫폼에 이식하기 어렵다.
스레드를 당장 처리헤야 할 작업이 없다면 실행되서는 안된다.
Thread.yield와 스레드 우선순위는 절대로 의존해서는 안된다.