Java ‐ 쓰레드 안전성 수준을 문서화하라[Effective Java Item 82] - thought-corner/Backend-PlayGround GitHub Wiki
스레드 안전성 수준의 5가지 단계
1. 불변(Immutable)
- 상수와 같아서 내부 상태가 변하지 않는다.
- 외부 동기화가 필요 없는 가장 완벽한 안전 상태
- ex :
String,BigInteger,Integer - 전역 변수를 final로 선언하고 수정자(setter)를 두지 않는다.
2. 무조건적 쓰레드 안전(Unconditionally Thread-Safe)
- 인스턴스 내부 상태가 가변이지만 내부에서 정교하게 동기화를 처리하여 외부에서 별도 락 없이 동시 사용이 가능하다.
- ex :
ConcurrentHashMap,AtomicInteger - 별도 주석 없이 타입 자체나 구조로 안전함을 드러낸다.
3. 조건부 쓰레드 안전(Conditionally Thread-Safe)
- 일부 메서드는 그냥 써도 안전하지만, 특정 메서드를 연달아 호출할 때는 외부에서 수동으로 락을 쥐어야 한다.
- ex :
Collections.synchronizedMap()이 반환하는 컬렉션 - 반드시 어떤 락을 얻어야 하는지 문서화를 해 둘 필요가 있다.
4. 쓰레드 안전하지 않음(Not Thread-Safe)
- 내부 상태가 가변이며 내부 동기화가 전혀 없다.
- 멀티쓰레드 환경에서 쓰려면 외부에서 호출 시점에 동기화 블록으로 감싸야 한다.
- ex :
ArrayList,HashMap - 싱글톤 빈의 멤버 변수로 쓰지 않거나 지역 변수로만 활용한다.
5. 쓰레드 적대적(Thread-Hostile)
- 외부에서 아무리
synchronized로 락을 걸어도 멀티 쓰레드 환경에서 오동작하거나 고장난다. - 내부 동기화 없이 공유 전역 변수를 수정하는 레거시 메서드
- 실무에서 발견 즉시 리팩토링해서 제거해야하는 대상
서비스 안정성을 높이는 비공개 락 객체 (Private Lock Object) 패턴
// Good
public class SubSystem {
// 1. 외부에서 절대 접근할 수 없는 비공개 락 객체 선언 (final 필수)
private final Object lock = new Object();
public void process() {
// 2. 클래스 내부에서만 이 객체를 조준하여 동기화 수행
synchronized(lock) {
// 비즈니스 로직 진행
}
}
}
- 클라이언트가 객체 동기화에 관여할 수 없다.
- 무조건적 쓰레드 안전 클래스에서만 사용할 수 있다. 조건부 쓰레드 안전 클래스에서는 사용할 수 없다.