IT/Programming / / 2023. 4. 26. 13:19

<Effective Java> RULE 70 스레드 안전성에 대해 문서로 남겨라

반응형

 

병렬적으로 사용해도 안전한 클래스가 되려면, 어떤 수준의 스레드 안전성을 제공하는 클래스인지 문서에 명확히 남겨야 한다.

 

변경 불가능 : 이 클래스로 만든 객체들은 상수다. 따라서 외부적인 동기화 메커니즘 없이도 병렬적으로 이용 가능하다.

· String, Long, BigInteger,..

 

무조건적 스레드 안전성 : 이 클래스의 객체들은 변경이 가능하지만 적절한 내부 동기화 메커니즘을 갖추고 있어서 외부적으로 동기화 메커니즘을 적용하지 않아도 병렬적으로 사용할 수 있다.

· Random, ConcurrentHashMap..

 

조건부 스레드 안전성 : 무조건적 스레드 안전성과 거의 같은 수준이나 몇몇 스레드는 외부적 동기화가 없이는 병렬적으로 사용할 수 없다. 아래와 같은 객체 반복자는 외부적 동기화 없이는 병렬적으로 사용할 수 없다.

· Collections.synchronized 계열메서드가 반환하는 포장 객체들..

 

스레드 안전성 없음 : 이 클래스의 객체들은 변경 가능하다. 해당 객체들은 병렬적으로 사용하려면 클라이언트는 메서드를 호출하는 부분을 클라이언트가 선택한 외부적 동기화 수다능로 감싸야 한다.

· ArrayList나 HashMap같은 컬렉션 구현체

 

다중 스레드에 적대적 : 설사 메서드를 호출하는 모든 부분을 외부적 동기화 수단으로 감싸더라도 안전하지 않다. 동기화 없이 정적 데이터를 변경하기 때문이다. 누구도 고의로 이러하게 만들지 않고 개발의 실수이다.

· System.runFinalizersOnExit가 스레드에 적대적이며, 현재는 폐기 되었다.

 

조건부 스레드 안전성 클래스에 대한 문서를 만들 때는 신중해야 한다.

· 어떤 순서로 메서드 호출할 때 외부 동기화 메커니즘을 동원해야하는지.

· 그 순서로 메서드를 실행하려면 어떤 락을 사용해야 하는지.

· 다른 객체에 대한 뷰 역할을 하는 객체일 경우 원래 객체에 대해 동기화를 해야한다.

Map<K, V> m = Collections.syncronizedMap(new HashMap<K, V>());

Set<K> s = m.KeySet(); //동기화 블록 안에 있을 필요 없다.

syncronized(m){ //s가 아니라 m에 대해 동기화
    for(K key : s){
        key.f();
}
 

· enum같은 변경 불가능 클래스에는 변경 불가능성을 문서에 남길 필요가 없다.

· 반환값 자료형을 보고 명확하게 알 수 있는경우를 빼고 정적 팩토리 안에서 자기가 반환하는 객체에 스레드 안전성을 문서에 남겨야 한다.

// Dos 공격을 피하기 위한 private 객체 락
private final Object lock = new Object();

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

결론

· 스레드 안전성 어노테이션을 이용하건 간에 모든 클래스는 자신의 스레드 안전성 수준을 문서로 분명히 밝혀야 한다.

· synchronized키워드는 문서에 아무런 역할을 하지 못한다.

· 조건부 스레드 안전성을 제공하는 클래스는 어떤 순서로 메서드를 호출할 때 외부적 동기화가 필요한 문서에 밝혀야하고 그때 어떤 락을 획득하게 되는지도 밝혀야한다.

· 무조건적 스레드 안전성을 제공하는 클래스를 구현할때는 메서드를 synchronized로 선언하는 대신 private 락 객체를 이용하면 어떨지 따져보라

 

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유