티스토리 뷰

728x90
반응형

wait와 notify보다는 동시성 유틸리티를 애용하라


  • 자바 5에서 도입된 고수준의 동시성 유틸리티가 이전의 wait, notify로 하던 일들을 대신하게 되었습니다. wait와 notify는 사용하기 상당히 까다롭기 때문에 고수준의 동시성 유틸리티를 사용하는게 좋습니다.
  • java.util.concurrent 패키지에는 고수준 유틸리티를 세 범주로 나눌 수 있습니다. 실행자 프레임워크, 동시성 컬렉션, 동기화 장치로 구분할 수 있습니다.

 

💡 동시성 컬렉션

  • 동시성 컬렉션은 List, Queue, Map과 같은 표준 컬렉션 인터페이스에 동시성을 가미해 구현한 고성능 컬렉션입니다. 높은 동시성을 달성하기 위해 동기화를 각자의 내부에서 수행하며, 동시성 컬렉션에서 동시성을 무력화하는건 불가능하며, 외부에서 락을 추가로 사용하면 오히려 속도가 느려집니다.
  • 동시성 컬렉션에서 동시성을 무력화할 수 없기 때문에 여러 메서드를 원자적으로 묶어 호출하는 일 역시 불가능합니다. 그래서 여러 기본 동작을 하나의 원자적 동작으로 묶는 상태 의존적 수정 메서드들이 추가되었습니다.
  • 참고로 Collections.synchronizedMap 보다는 ConcurrentMap을 사용하는게 좋습니다.
private static final ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();

public static String internV1(String s) {
    String cacheValue = map.putIfAbsent(s, s);
    return  cacheValue == null ? s : cacheValue;
}

// ConcurrentHashMap은 get같은 검색에 최적화 되어 있기 때문에 아래 메서드가 더 빠릅니다.
public static String internV2(String s) {
    String result = map.get(s);
    if (result == null) {
        result = map.putIfAbsent(s, s);
        if (result == null) {
            result = s;
        }
    }
    return result;
}

 

💡 동기화 장치

  • 동기화 장치는 스레드가 다른 스레드를 기다릴 수 있도록 합니다.
  • 예를들어 Queue를 확장한 BlockingQueue도 확장된 기능 중 take라는 기능이 있는데, 큐의 첫번째 원소를 꺼내는 기능으로 만약 큐가 비어있다면 새로운 원소를 추가될 때까지 기다립니다. 그렇기 때문에 BlockingQueue는 작업 큐로 쓰기 적당하며 ThreadPoolExecutor나 실행자 서비스 구현체에서 BlockingQueue를 사용합니다.

 

💡 notify 대신 notifyAll

  • 일반적으로 notify보다는 notifyAll 메서드를 호출하는게 더 안전하다고 합니다.
  • notifyAll은 관련 없는 스레드가 실수로 혹은 악의적으로 wait 메서드를 호출하는 공격으로부터 보호할 수 있다고 합니다.
  • 깨어나야 하지만 깨어나지 못한 스레드를 깨울 수 있습니다. 깨우는 도중 다른 스레드가 깨워질 수 있지만 조건이 충족되지 않은 상태라면 그 스레드들은 다시 대기하게 될 것입니다.
  • 하지만 모든 스레드가 같은 조건을 기다리고, 조건이 한번 충족될때마다 하나의 스레드만 깨우는 경우라면 최적화하기 위한 용도로 notify를 사용해도 된다고 합니다.

 

✔️ 정리

  • 우리는 고수준의 동시성 유틸리티가 있기 때문에 notify와 wait를 직접적으로 혹은 자주 사용할 일은 드물어 보입니다.
  • 하지만 래거시 프로그램을 유지보수 해야한다면 wait는 반드시 대기 반복문(wait loop) 관용구를 사용해야 합니다.
  • notify 보다는 notifyAll을 사용하고 혹시라도 notify를 사용해야 한다면 응답 불가 상태에 빠지지 않도록 주의해야 합니다.

 

 

 

 

 

 

 

728x90
반응형