일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- spring cloud
- Serial GC
- Java
- Action Pattern
- Transaction Pattern
- MSA
- Resilinece4j
- saga pattern
- 배치
- 타입스크립트
- TypeScript
- spring batch
- JPA
- 체인 패턴
- 알고리즘
- java 정렬
- zipkin
- 멀티스레드
- 디자인 패턴
- 디자인패턴
- The law of Demeter
- thread
- 생산자 소비자 패턴
- Parallel Old GC
- 스레드
- 사가 패턴
- 키클락
- Spring Cloud Netfilx Eureka
- Spring Boot Actuator
- 스프링 배치
- Today
- Total
PSD( Private-Self-Development )
Callable, Future, Executors, Executor, ExecutorService, ScheduledExecutorService 본문
Callable, Future, Executors, Executor, ExecutorService, ScheduledExecutorService
chjysm 2023. 7. 12. 11:48Thread와 Runnable의 단점 및 한계
- 지나치게 저수준의 API(스레드의 생성)에 의존함
- 값의 반환이 불가능
- 매번 스레드 생성과 종료하는 오버헤드가 발생
- 스레드들의 관리가 어려움
이와 같은 Thread와 Runnable의 한계점 극복을 위해 JAVA 5 이후 버전부터
Callable, Future, Executors, Executor, ExecutorService, ScheduledExecutorService을 지원하게 되었다.
무엇인지 어떤 단점을 어떻게 개선하였는지 알아보자.
Callable, Future
- 값의 반환이 불가능
단점을 극복하기 위해
JAVA 5에 추가된 제네릭을 사용해 실행 결과 값을 반환받을 수 있도록 하는 인터페이스
Callable 인터페이스
제네릭을 사용해 실행 결과 값을 반환받을 수 있도록 하는 인터페이스
해당 인터페이스의 구현체인 [작업]을 사용한다.
하지만 [작업]은 가용 스레드 가 없어 실행이 미뤄지거나 작업이 오래 걸릴 수 도 있기 때문에
완료된 Callable 의 실행 결괏값을 구하기 위해 Future를 사용한다.
public interface Callable<V> {
V call() throws Exception;
}
Future 인터페이스
Callable 의 실행 결괏값을 구하기 위하여
비동기 작업을 가지고 있어 이러한 비동기 작업의 현재 상태를 확인하고, 기다리고, 결과를 얻는 방법을 제공한다.
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning); // 작업 취소
// mayInterruptIfRunning
// true : 스레드 바로 interrupt 발생 시킨다.
// false : 진행중 작업이 끝날 때 까지 대기
boolean isCancelled(); // 작업 취소 여부
boolean isDone(); // 작업 완료 여부
V get() throws InterruptedException, ExecutionException; // 블로킹 방식으로 결과 가지고옴
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
// 타임아웃 설정 가능
}
Executors, Executor, ExecutorService, ScheduledExecutorService
- 지나치게 저수준의 API(스레드의 생성)에 의존함
- 매번 쓰레드 생성과 종료하는 오버헤드가 발생
- 스레드들의 관리가 어려움
단점을 극복하기 위해 JAVA 5 이상부터 제공하는 인터페이스 와 클래스이다.
Executor
스레드 풀 구현을 위한 인터페이스
스레드는 크게 작업의 등록과 실행으로 나누어지는데,
여기서 Executor 은 작업의 실행만을 담당한다.
public interface Executor {
void execute(Runnable command);
}
스레드 풀?
매번 스레드를 사용할 때마다 생성/제거를 한다면 리소스 낭비가 되고, 관리하기도 힘들기 때문에
이러한 단점을 극복하기 위해 특정 개수만큼 스레드를 생성해 놓고
작업을 할당하도록 하는 스레드의 묶음이다.
ExecutorService
작업의 등록을 위한 인터페이스
Executor을 상속받아서 작업의 등록뿐 아니라 실행을 위한 책임도 갖는다.
스레드 풀은 기본적으로 이 ExecutorService를 구현하여 사용한다.
대표적으로 ThreadPoolExecutor 가 있다.
내부 구조
- 블록킹 큐
- 스레드 최대 수 가 넘는 작업이 들어온다면 이 블록킹 큐에서 대기하다가
작업이 끝난 스레드에 해당 작업을 할당한다.
- 스레드 최대 수 가 넘는 작업이 들어온다면 이 블록킹 큐에서 대기하다가
- 스레드 풀
- 한 번에 띄울 수 있는 스레드들로 구성
제공 기능은 크게 두 가지 종류로 나뉜다.
- 라이프 사이클 관리를 위한 기능
- shutdown
- 새로운 작업 할당 하지 않겠다.
- 호출 전 작업들은 그대로 실행이 끝나고 종료
- 호출하지 않는다면 계속 다음 작업을 대기하므로 꼭 호출해줘야 한다.
- shutdownNow
- shutdown 기능에 더해 호출 전 작업들을 바로 Interrupt 시킨다.
- 대기 중이던 작업 목록을 반환한다.
- isShutdown
- Executor의 shutdown 여부 반환
- isTerminated
- shutdown 실행 후 모든 작업의 종료 여부 반환
- awaitTermination
- shutdown 실행 후, 지정한 시간 동안 모든 작업이 종료될 때까지 대기함
- 지정한 시간 내에 모두 완료되었는지 여부를 반환함
- shutdown
- 비동기 작업을 위한 기능
- submit
- 실행할 적업들을 추가
- 작업의 상태와 결과를 포함하는 Future 반환
- invokeAll
- 모든 결과가 나올 때까지 대기하는 블로킹 방식의 요청
- 주어진 작업들을 모두 실행하고, 전부 끝나면 각각의 상태와 결과를 갖는 List <Future> 반환
- invokeAny
- 가장 빨리 실행된 결과가 나올 때까지 대기하는 블로킹 방식의 요청
- 동시에 주어진 작업들을 모두 실행하고, 가장 빨리 완료된 하나의 결과를 Future로 반환
- submit
ScheduledExecutorService
ExecutorService를 상속받는 인터페이스
특정 시간 이후에 혹은 특정 주기로 작업일 실행하는 메서드가 추가되었다.
- schedule
- 특정 시간 이후에 작업을 실행
- scheduleAtFixedRate
- 특정 시간 이후 처음 작업을 실행
- 작업이 실행되고 특정 시간마다 작업을 실행
- scheduleWithFixedDelay
- 특정 시간 이후 처음 작업을 실행
- 작업이 완료되고 특정 시간이 지나면 작업을 실행
Executors
Executor, ExecutorService, ScheduledExecutorService의 팩토리 클래스
해당 구현체들을 손쉽게 제공한다.
- newFixedThreadPool
- 고정된 스레드 개수를 갖는 스레드 풀을 생성
- ExecutorService 인터페이스를 구현한 ThreadPoolExecutor 객체 생성
- newCachedThredPool
- 필요할 때 필요한 만큼의 스레드를 풀 생성
- 이미 생성된 스레드가 있다면 이를 재활용
- newScheculedThreadPool
- 일정 시간 뒤 혹은 주기적으로 실행되어야 하는 작업을 위한 스레드 풀을 생성
- ScheduledExecutorService 인터페이스를 구현한 ScheduledThreadPoolExecutor 객체 생성
- newSingleThreadExecutor, newSingleThreadScheduledExecutor
- 1개의 스레드만을 갖는 스레드 풀을 생성
- 각각 newFixedThreadPool와 newScheculedThreadPool에 1개의 스레드만을 생성하도록 한 것
Future 의 단점 및 한계
- 결과를 얻으려면 블로킹 방식으로 대기해야 한다
- 외부에서 완료 시킬 수 없다
- 여러 Future를 조합할 수 없다.
- 여러 작업을 조합하거나 예외처리 할 수 없다.
이러한 단점을 보완하기 위해 JAVA8 에 추가된 CompletableFuture 이다.
참조
'Backend > Thread' 카테고리의 다른 글
생산자 소비자 패턴 (2) | 2024.08.28 |
---|---|
BlockingQueue 와 DelayQueue (0) | 2024.08.26 |
CompletableFuture (0) | 2023.07.12 |
Thread 와 Runnable (0) | 2023.07.11 |
Thread 란? (0) | 2022.11.15 |