작업 큐를 손수 만드는 일은 삼가야 하고, 스레드를 직접 다루는 것도 일반적으로 삼가야 한다. 실행자 프레임워크를 사용하여 작업 단위와 실행 단위로 이용하자.
실행 단위
ExecutorService(실행서비스)
- 특정 태스크가 완료되기를 기다린다.
- 태스크 모음 중 아무것 하나 혹은 모든 태스크가 완료되기를 기다린다.
- 실행자 서비스가 종료하기를 기다린다.
- 완료된 태스크들의 결과를 차례로 받는다.
- 태스크를 특정 시간에 혹은 주기적으로 실행하게 한다.
큐를 둘 이상의 스레드가 처리하게 하고 싶다면 간단히 다른 정적 팩터리를 이용하여 다른 종류의 실행자 서비스(스레드 풀)를 생성하면 된다. 스레드 풀의 스레드 개수는 고정할 수도 있고 필요에 따라 늘어나거나 줄어들게 설정할 수도 있다.
ThreadPoolExecutor
- 스레드 풀 동작을 결정하는 거의 모든 속성을 설정할 수 있다.
Executors.newCachedThreadPool
- 작은 프로그램이나 가벼운 서버라면 사용하기 좋다.
- 요청받는 태스크들이 큐에 쌓이지 않고 즉시 스레드에 위임돼 실행된다.
- 가용한 스레드가 없다면 새로 하나를 생성한다.
- 서버가 아주 무겁다면 CPU 이용률이 100퍼로 치닫고, 새로운 태스크가 도착하는 족족 다른 스레드를 생성하며 상황을 더욱 악화시킨다.
Executors.newFixedThreadPool
- 스레드 개수를 고정하여 사용한다.
작업 단위
작업 단위는 태스크로 말하며 Runnable, Callable가 있다. 태스크를 수행하는 것이 실행 서비스이다.
- 태스크 수행을 실행자 서비스에 맡기면 원하는 태스크 수행 정책을 선택할 수 있고, 생각이 바뀌면 언제든지 변경할 수 있다.
- 자바7부터 포크-조인 태스크를 지원하도록 확장되었다. 포크-조인 태스크는 포크-조인 풀이라는 특별한 실행자 서비스가 실행해준다.
- PorkJoinPool을 구성하는 스레드들이 이 태스크들을 처리하며, 일이 먼저 끝낸 스레드는 다른 스레드의 남은 태스크를 가져와 대신 처리할 수 있다. 이렇게 하여 모든 스레드가 바쁘게 움직여 CPU를 최대한 활용하면서 높은 처리량과 낮은 지연시간을 달성한다.
- 병렬 스트림을 사용하면 된다.
'Java > EffectiveJava' 카테고리의 다른 글
Effective Java Item86. Serializable을 구현할지는 신중히 결정하라. (0) | 2025.03.23 |
---|---|
Effective Java Item85. 자바 직렬화의 대안을 찾으라. (0) | 2025.03.23 |
Effective Java Item79. 과도한 동기화는 피하라. (0) | 2025.03.16 |
Effective Java Item68. 일반적으로 통용되는 명명 규칙을 따르라. (1) | 2025.03.09 |
Effective Java Item67. 최적화는 신중히 하라. (0) | 2025.03.09 |