Skip to content

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

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) {
		}
}

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

💡 새롭게 알게 된 점

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

📚 정리

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


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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions