개발하는 두더지

[Effective Java 규칙69] wait이나 notify 대신 병행성 유틸리티를 이용하라 본문

Java,Android

[Effective Java 규칙69] wait이나 notify 대신 병행성 유틸리티를 이용하라

덜지 2018. 11. 20. 16:10

[Effective Java 규칙69] wait이나 notify 대신 병행성 유틸리티를 이용하라

Effective Java 2/E 책과 구글링을 통해 내용을 정리하고 개인적인 견해가 포함된 글입니다.



자바 1.5부터 고수준 병행성 유틸리티 포함되어있어서 wait과 notify를 사용해서 구현해야될 일들을 대신하게 해준다. 제목처럼 wait과 notify를 정확하게 사용하는 것이 어렵기때문에 고수준 병행성 유틸리티를 반드시 사용해야 한다.


java.util.concurrent에 포함된 고수준 병행성 유틸리티들은 실행자 프레임워크(executor framework), 병행 컬렉션(concurrent collection), 동기자(synchronizer) 이다. 이미 사용하고 있는 것일 수도 있지만 이번 규칙에서 한번 다뤄본다.


병행 컬렉션은 List, Queue, Map 등의 표준 컬렉션 인터페이스에 대한 고성능 병행 컬렉션 "구현체"을 제공한다. ConcurrentMap과 같은 클래스 처럼 말이다. 이 컬렉션들은 병행성을 높기이 위해 동기화를 "내부적으로" 처리한다. 컬렉션 외부에서 병행성을 처리하는 것은 불가능하다. 락을 걸어봐야 아무 효과도 없고 프로그램만 느려진다. 


상태 종속 변경 연산(state dependent modify operation) 라는 기능을 제공한다.

예를들어 ConcurrentMap은 Map을 확장하며 몇가지 메서드를 만들었는데 그중 한가지인 putIfAbsent라는 메서드가 있다. 이 메서드는 키에 해당하는 값이 없을 때만 주어진 값이 저장되고, 키에 값이 있다면 새로운 값을 저장하는 것이 아닌 저장되어 있는 값을 반환해주는 기능이다. Map에는 이런 기능이 없기때문에 직접 구현해줘야 하는데 이 컬렉션에서는 제공해주는 메서드이므로 이용하면 된다.


확실한 이유가 없다면 Collections.synchronizedMap이나 Hashtable 대신 ConcurrentHashMap을 사용해야 한다. 구식이 되어버린 동기화 맵을 병행 맵으로 바꾸기만 해도 병렬 프로그램의 성능은 상당하게 올라간다. 일반적으로 보자면 외부적인 동기화 메커니즘이 필요한 컬렉션 대신에 반드시 병행 컬렉션을 이용하도록 해야 한다.


또한 blocking operation이 가능하도록 확장된 컬렉션도 있다. BlockingQueue는 Queue를 확장하여 take와 같은 메서드를 추가하였는데 이 메서드는 큐의 맨 앞 원소를 제거한 다음 반환하는데 큐가 비어있는 경우 대기를 하는 기능이다.  ThreadPoolExecutor를 비롯한 대부분의 ExecutorService는 BlockingQueue를 사용하고 있다.



요약하자면, wait이나 notify를 사용하는 것은 병행성 어셈블리 언어를 사용해 코딩하는 것과 같은 비유이다. 그래서 새로 프로젝트를 만든다면 wait이나 notify를 사용하지말고 고성능 병행 컬렉션을 이용하자









Comments