반응형
이 포스팅에서 작성하는 내용은 EFFECTIVE JAVA(이펙티브자바) 에서 발췌하였습니다.
아이템 80. 스레드보다는 실행자, 태스크, 스트림을 이용하라
java.util.concurrent
- 동시성 작업 시, 작업 큐를 사용하면 안전 실패나 응답 불가와 같은 경우에 대한 대비를 해야하는데, java.util.concurrent 패키지를 사용하면 좋다.
- 이 패키지는 실행자 프레임워크라고 하는 인터페이스 기반의 유연한 태스크 실행 기능을 담고 있다.
- 그래서 아이템 49의 단순한 작업 큐(work queue) 보다 뛰어난 큐를 아래처럼 한 줄로 생성하고 사용할 수 있다.
ExecutorService exec = Executors.newSingleThreadExecutor(); // 작업 큐 생성
exec.execute(runnable) // 이 실행자에 실행할 task를 넘김
exec.shutdown(); // 실행자를 종료
- 실행자 서비스의 다양한 기능
- 특정 태스크가 완료되기를 기다린다.
- 태스크 모음 중 아무것 하나(invokeAny 메서드) 혹은 모든 태스크(invokeAll 메서드)가 완료되기를 기다린다.
- 실행자 서비스가 종료하기를 기다린다(awaitTermination 메서드).
- 완료된 태스크들의 결과를 차례로 받는다(ExecutorCompletionService 이용).
- 태스크를 특정 시간에 혹은 주기적으로 실행하게 한다(ScheduledThreadpoolExecutor 이용)
java.util.concurrent.Executors
- 큐를 둘 이상의 스레드가 처리하게 하고 싶다면 간단히 다른 정적 팩터리를 이용하여 다른 종류의 실행자 서비스(스레드 풀)를 생성하면 된다.
- 스레드 풀의 스레드 갯수는 고정할 수도 있고, 유동적으로 상황에 맞게 설정되게 할 수도 있다.
- 실행자 대부분은 java.util.concurrent.Executors의 정적 팩터리들을 이용해 생성할 수 있다.
- 이 클래스로는 스레드 풀 동작을 결정하는 거의 모든 속성을 설정할 수 있다.
Executors.newCachedThreadPool
- 특별히 설정할게 없고 일반적인 용도에 적합하다.
- 무거운 프로뎍선 서버에는 좋지 않다.
- CachedThreadPool에서는 요청받은 태스크들이 큐에 쌓이지 않고 즉시 스레드에 위임돼 실행된다.
- 가용한 스레드가 없다면 새로 하나를 생성한다.
- 서버가 아주 무겁다면 CPU 이용률이 100%로 치닫고, 새로운 태스크가 도착하는 족족 또 다른 스레드를 생성하며 상황을 더욱 악화시킨다.
- 따라서 무거운 프로덕션 서버에서는 스레드 개수를 고정한 Executors.newFixedThreadPool을 선택하거나 완전히 통제할 수 있는 ThreadPoolExecutor를 직접 사용하는 편이 낫다.
태스크
- 스래드를 직접 다루면 Thread가 작업 단위와 수행 메커니즘 역할을 모두 수행하게 된다.
- 반면, 실행자 프레임워크에서는 작업 단위와 실행 메커니즘이 분리된다.
- 태스트 : 작업 단위를 나타내는 핵심 추상 개념이며, 두 가지가 있다.
- Runnable
- Callable(Runnable과 비슷하지만 값을 반환하고 임의의 예외를 던질 수 있음)
- 태스크 수행을 실행자 서비스에 맡기면 원하는 태스크 수행 정책을 선택할 수 있고, 생각이 바뀌면 언제든 변경할 수 있다.
- 핵심은 실행자 프레임워크가 작업 수행을 담당해준다는 것이다.
Fork-Join Framework
- 자바 7부터 지원
- 포크-조인 태스크는 포크-조인 풀이라는 특별한 실행자 서비스가 실행해준다.
- 포크-조인 태스크의 인스턴스는 작은 하위 태스크로 나뉠 수 있으며, ForkJoinPool을 구성하는 스레드들이 이 작은 하위 태스크를 처리하고, 다른 태스크도 도와준다.
- 각 스레드들이 처리한 결과를 취합하는 작업도 진행한다.
- 자세한 내용 참고) https://devfunny.tistory.com/606
반응형
'BE > Java' 카테고리의 다른 글
[Effective Java] 아이템 82. 스레드 안정성 수준을 문서화하라 (0) | 2022.12.23 |
---|---|
[Effective Java] 아이템 81. wait와 notify보다는 동시성 유틸리티를 애용하라 (0) | 2022.12.22 |
[Effective Java] 아이템 79. 과도한 동기화는 피하라 (0) | 2022.12.20 |
[Effective Java] 아이템 78. 공유 중인 가변 데이터는 동기화해 사용하라 (0) | 2022.12.19 |
[Effective Java] 아이템 77. 예외를 무시하지 말라 (0) | 2022.12.16 |