Notice
Recent Posts
Recent Comments
Link
개발자는 기록이 답이다
패스트캠퍼스 환급챌린지 5일차 미션 (2월 5일) : Spring Webflux 완전 정복 : 코루틴부터 리액티브 MSA 프로젝트까지 강의 후기 본문
패스트캠퍼스
패스트캠퍼스 환급챌린지 5일차 미션 (2월 5일) : Spring Webflux 완전 정복 : 코루틴부터 리액티브 MSA 프로젝트까지 강의 후기
slow-walker 2024. 2. 5. 19:51
Future와 CompletionStage
1. CompletableFuture
- 2014년에 발표된 java 8에 처음 도입
- 비동기 프로그래밍 지원
- Lambda, Method reference 등 Java 9의 새로운 기능 지원
- Lambda : 함수형 인터페이스에 좀 더 간소화된 표현식
- Method reference : 콜론 2개(::)를 이용해서 함수에 대한 참조를 간결하게 표현
- static method reference
- instance method reference
- constructor method reference
2. Future 인터페이스
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
3. ExecutorService
비동기 논블로킹으로 되어있는 연산자는 별도의 스레드가 필요한 경우가 많다.
스레드를 직접 new Thread ()를 이용해서 실행해도 되지만, 스레드를 많이 사용해야되거나 스레드를 직접 관리하는게 쉽지 않기 때문에 스레드 풀을 사용하는 경우가 많다. 이런 스레드 풀을 쉽게 제공하고 관리할 수 있는게 ExecutorService이다.
- 스레드 풀을 이용하여 비동기적으로 작업을 실행하고 관리
- 별도의 스레드를 생성하고 관리하지 않아도 되므로, 코드를 간결하게 유지 가능
- ExecutorService를 사용하면 ExecutorService가 자체적으로 스레드풀을 만들면서 스레드를 생성하긴 하지만
- 직접 스레드를 만들어서 인스턴스 변수나 로컬 변수를 두고 관리할 필요가 없이 알아서 관리가 된다.
- 스레드 풀을 이용해 자원을 효율적으로 관리
- 동적으로 만들었다가 제거하는 스레드 풀도 있고 효율적으로 관리할 수 있는 장점이 있다
4. ExecutorService 메소드
public interface ExecutorService extends Executor {
void execute(Runnable command);
<T> Future<T> submit(Callable<T> task);
void shutdown();
}
- execute : Runnable 인터페이스를 구현한 작업을 스레드 풀에서 비동기적으로 실행
- submit : Callable 인터페이스를 구현한 작업을 스레드 풀에서 비동기적으로 실행하고, 해당 작업의 결과를 Future<T>로 반환
- shutdown : ExecutorService를 종료. 더 이상 task를 받지 않는다.
- 스레드 풀을 다 사용하고 나면 항상 shutdown을 해야 한다.
- shutdown이 되지 않았으면 main스레드가 종료되는 시점에 ExecutorService가 아직 안 닫힌걸 보고 아직 할 작업이 남았다고 생각하고 무한정 대기하게 된다.
- ExecutorService를 다 사용했다면 maint스레드 마지막에 shutdown을 해야 한다
- 대기큐에 남아있는 작업이 끝날때까지 계속 기다리기 때문에, awaitTermination을 해주어야 한다.
5. Executors - ExecutorService 생성
각각의 5개 메소드들은 Executors를 통해 접근할 수 있고, ExecutorService를 만들 수 있는 메소드를 가진 Factory객체이다.
- newSingleThreadExecutor : 단일 스레드로 구성된 스레드 풀 생성, 한 번에 하나의 작업만 실행
- newFixedThreadPool : 고정된 크기의 스레드 풀 생성. 크기는 인자로 주어진 n과 동일
- 예상 가능한 스레드일 경우 최적화 가능
- newCachedThreadPool : 사용 가능한 스레드가 없다면 새로 생성해서 작업을 처리하고, 있다면 재사용. 스레드가 일정 시간 사용되지 않으면 회수
- 요청이 엄청 많이 들어오는 경우 동적으로 스레드 개수를 관리할 수 있기 때문에 최대 OOME가 발생할 수도 있어서
- 예상 가능한 범위의 스레드일 경우에만 사용해야 한다
- newScheduledThreadPool : 스케줄링 기능을 갖춘 고정 크기의 스레드풀 생성. 주기적이거나 지연이 발생하는 작업을 실행
- 특정 간격을 두고 실행이 되는 작업을 할때 사용
- newWorkStealingPool : work steal 알고리즘을 사용하면 ForkJoinPool 생성
6. FutureHelper
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class FutureHelper {
public static Future<Integer> getFuture() {
var executor = Executors.newSingleThreadExecutor();
try {
return executor.submit(() -> {
return 1;
});
} finally {
executor.shutdown();
}
}
public static Future<Integer> getFutureCompleteAfter1s() {
var executor = Executors.newSingleThreadExecutor();
try {
return executor.submit(() -> {
Thread.sleep(1000);
return 1;
});
} finally {
executor.shutdown();
}
}
public static Future<Integer> getFutureWithException() {
var executor = Executors.newSingleThreadExecutor();
try {
return executor.submit(() -> {
throw new RuntimeException("Error");
});
} finally {
executor.shutdown();
}
}
}
- getFuture : 새로운 스레드를 생성하여 1을 반환
- getFutureCompleteAfter1S : 새로운 스레드를 생성하고 1초 대기 후 1을 반환
7. Future : isDone(), isCancelled()
- Future의 상태 반환
- isDone : task가 완료되었다면, 원인과 상관없이 true 반환
- cancel이 되서 작업이 더이상 진행되지 않아도 isDone
- complete되거나 exception이 발생해서 더 이상 진행되지 않아도 isDone
- 즉, 지금 실행중인 상태가 아니라면 true
- isCancelled : task가 명시적으로 취소된 경우, true 반환
8. Future : get()
- 결과를 구할 때 까지 thread가 계속 block
- future에서 무한 루프나 오랜 시간이 걸린다면 thread가 blocking 상태 유지
※ 본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다. https://bit.ly/48sS29N