Skip to content

[아이템 82] 스레드 안전성 수준을 문서화하라 #103

@jupyter471

Description

@jupyter471

📌 아이템 82 스레드 안전성 수준을 문서화하라

✨ 핵심 내용

한 메서드를 여러 스레드가 동시에 호출할 때 그 메서드가 어떻게 동작하느냐는 해당 클래스와 이를 사용하는 클라이언트 사이의 중요한 계약과 같다

문서에 언급이 없으면 사용자는 나름의 가정을 해야한다. 만약 가정이 틀리면 동기화를 충분히 하지 못하거나, 지나치게 한 상태이다

→ 심각한 오류로 이어진다

  • 자바독이 기본 옵션으로 생성한 API 문서에는 synchronized 한정자가 포함되지 않는다

    → 메서드 선언에 synchronized 한정자를 선언할지는 구현 이슈일 뿐 API에 속하지 않음!

<스레드 안정성 수준>

  • 불변
  • 무조건적 스레드 안전 : 외부 동기화 없이 동시에 사용 가능
  • 조건부 스레드 안전 : 일부 메서드는 외부 동기화 필요
    • 어떤 순서로 호출할 때 외부 동기화가 필요한지
    • 그 순서로 호출하려면 어떤 락 혹은 락들을 얻어야하는지 알려야함
  • 스레드 안전하지 않음 : 외부 동기화 필요
  • 스레드 적대적 : 모든 메서드 호출을 외부 동기화로 감싸더라도 멀티 스레드 환경에서 안전하지 않다

synchronizedMap - API 문서

synchronizedMap이 반환한 맵의 컬렉션 뷰를 순회하려면 반드시 그 맵을 락으로 사용해
수동으로 동기화하라

Map<K, V> m = Collections.synchronizedMap(new HashMap<>());
Set<K> s = m.keySet(); // 동기화 블록 밖에 있어도 된다
...
synchronized(m) { // s가 아닌 m을 사용해 동기화해야 한다!
for (K key : s)
   [key.f](http://key.fo/)();
}
이대로 따르지 않으면 동작을 예측할 수 없다.

클래스가 외부에서 사용할 수 있는 락을 제공하여 클라이언트에서 메서드 호출을 원자적으로 수행할 수 있다 (유연성)

그러나, 내부에서 처리하는 고성능 동시성 제어 메커니즘과는 혼용할 수 없다! 또한 클라이언트가 락을 오래 쥐고 놓지 않는 서비스 거부 공격을 수행할 수 있다

이를 막기 위해서는 synchronized 메서드 대신 비공개 락 객체를 사용해야한다

private final Object lock = new Object();

public void foo() {
		synchronized(lock) {
		}
}

→ 무조건적 스레드 안전 클래스에서만 사용 가능하다

💡 새롭게 알게 된 점

  • 학습하면서 이전과 다르게 이해한 점이나 새롭게 알게 된 개념을 공유해주세요.

📚 정리

모든 클래스가 자신의 스레드 안전성 정보를 명확히 문서화해야한다


📢 댓글로 각자의 학습 내용을 공유해주세요!

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions