JAVA/Effective Java
item 80. 스레드보다는 실행자, 테스크, 스트림을 애용하라
Garonguri
2022. 8. 31. 17:49
728x90
java.util.concurrent 패키지의 등장
: 실행자 프레임워크라고 하는 인터페이스 기반의 유연한 테스크 실행 기능 포함.
-> 뛰어난 작업 큐를 생성할 수 있게 되었다.
// 작업 큐 생성
ExecutorService exec = Executors.newSingleThreadExecutor();
// 실행자에 실행할 테스크를 넘기는 방법
exec.execute(runnable);
//실행자를 종료시키는 방법
exec.shutdown();
실행자 서비스의 주요 기능들
- get
- 특정 테스크가 완료되기를 기다림
- invokeAny / invokeAll
- 테스크 모음 중 아무거나 하나 or 모든 테스크가 완료되기를 기다림
- awaitTermination
- 실행자 서비스가 종료하기를 기다림
- ExecutorCompletionService
- 완료된 테스크들의 결과를 차례대로 받음
- ScheduledThreadPoolExecutor
- 테스크를 특정 시간 혹은 주기적으로 실행함
그 이외 지키면 좋은 것들
- 큐를 둘 이상의 스레드가 처리하게 하고 싶을 때
- 다른 정적 팩터리를 이용해 다른 종류의 실행자 서비스 생성
- 스레드 개수는 고정할 수도, 가변적으로 설정할 수 있음
- java.util.concurrent.Executors / ThreadPoolExecutor 클래스 사용
- 작은 프로그램이나 가벼운 서버의 경우
- Executors.newCachedThreadPool 사용
- 무거운 프로덕션 서버
- 스레드 개수를 고정한 Executors.newFixedThreadPool / ThreadPoolExecutor 사용
- 작업 큐를 손수 만드는 일과 스레드를 직접 다루는 일을 삼가하자.
- 왜?
- Thread는 작업의 단위(task) 와 그 작업을 실행하는 메커니즘이 결합되어 있음
- Executor Framework는 그 두개가 분리되어 있음
- 장점 : 작업이 언제 어떻게 실행될지에 대한 정책을 바꾸어도 작업을 구현한 코드에는 영향이 없다
- task의 종류
- Runnable, 값을 반환할 수 없으며 예외를 던질 수 없다.
- Callable, 값을 반환할 수 있으며 임의의 예외를 던질 수 있다.
- 왜?
- fork-join 테스크 지원
- Java 7부터 지원
- 과정
- fork-join Pool이라는 특별한 실행자 서비스가 실행해줌.
- fork-join task의 인스턴스는 작은 하위 테스크로 나뉠 수 있고, fork-join Pool을 구성하는 스레드들이 이 테스크를 처리한다.
- 일을 먼저 끝내면 다른 스레드의 남은 테스크를 가져와 대신 처리할 수도 있다.
- 장점
- 모든 스레드를 사용하기 때문에 CPU를 최대한 활용할 수 있다.
- 높은 처리량과 낮은 지연 시간 달성
728x90