01. 공유중인 가변 데이터는 동기화에 사용
공유 데이터
public synchronized static void threadRunner() throws InterruptedException{
int cnt = ThreadCounter.cnt;
TimeUtil.SECONDS.sleep(2);
ThreadCountter.cnt = cnt + 1;
}
여러 Thread가 가변데이터를 공유한다면 그 데이터를 읽고 쓰는 동작은 반드시 동기화하라.
가변 데이터는 단일 Thread에서만 사용하자
02. 과도한 동기화는 피하라
위험성
응답 블가와 안전 실패(safety failure)를 피하려면 동기화 메서드나 동기화 블록 안에서는
제어를 절대로 클라이언트에 양도하면 안 된다.
Fail fast - 가능한 빨리 실패를 노출하고, 전체 작업을 중지한다.
Safety failure(fail safe) - 실패 시에도 작업을 중단하지 않는다.
외계인 메서드 (alien method)
바깥에서 온 alien, 즉 무슨 일을 할지 알지 못하며, 통제할 수도 없다는 뜻.
통제 불능이기 때문에, alien method가 하는 일에 따라 예외를 일으키거나,
deadlock이 발생하거나, data가 훼손될 수 있다.
성능이 떨어지는 이유 - 동기화 영역에서는 가능한 일을 적게 하자
Deadlock (교착상태)
필요조건
1. 상호배제 (Mutual Exclusion)
2. 점유대기 (Hold and Wait)
3. 비선점 (No Preemption)
4. 순환대기 (Circular wait)
03. 스레드 보다는 실행자 태스크 스트림을 애용하라
Executor Frameword (실행자 Framework)
주요기능
- 특정 Task가 완료되기를 기다린다.
- Task 모음 중 아무 것 하나(invokeAny method) 혹은 모든 태스크 (invoke All method)가 완료되기를 기다린다.
- Executor service가 종료하기를 기다린다 (awaitTermination method)
- 완료된 Task의 결과를 차례로 받는다 (ExcutorCompletionService)
- Task의 Scheduling이 가능하다. (특정시간 혹인 주기적으로)
04. wait와 notify보다는 동시성 유틸리티를 애용해라
java.util.concurrent
- Executor framework
- Concurrent collection
- synchronizer
synchronizerMap vs ConcurrentHashMap
과거 단일 Thread에서는 HashMap, Multi thread에서는 SynchronizedMap을 사용
ConcurrentHashMap은 SynchronizedMap으로 감싼 HashMap이나 Hash 테이블보다 빠름.
(Map 전체에 synchronize lock을 거는 것이 아닌 map을 여러 조각으로 쪼개어 걸기 때문에 효율 증대)
05. 스레드 안전성 수준을 문서화하라
스레드 안정성이 높은 순
- 불변 (Immutable)
- 무조건적 스레드 안전 (Unconditionally thread-safe)
- 조건부 스레드 안전 (conditionally tread-safe)
- 스레드 안전하지 않음 (not thread-safe)
- 스레드 적대적 (tread-hostile)
06. 프로그램의 동작을 스레드 스케줄러의 기대지 말아라
스레드는 당장 처리해야 할 작업이 없다면 실행해서는 안 됨
Thread.yield() : 호출한 메서드를 대기로 돌리고, 동일한 우선순위, 높은 우선순위를 가지는 다른 스레드에게 기회를 양보한다.