owned this note
owned this note
Published
Linked with GitHub
# Java Future
- Java에서 `Future`는 비동기 계산의 아직 계산되지 않은 결과를 표현하는 인터페이스이다.
## Future의 주요 메소드
`Future` 인터페이스에는 다음과 같은 주요 메소드들이 있다.
- `get()`: 연산의 결과를 반환한다. 만약 연산이 아직 완료되지 않았다면, 완료될 때까지 기다린다. 이 메소드는 `Future`가 가지는 제네릭 타입의 객체를 반환한다.
- `get(long timeout, TimeUnit unit)`: 지정한 시간 동안만 결과를 기다리고, 그 시간이 지나면 `TimeoutException`을 던진다. 이 메소드는 시간이 지나면 `TimeoutException`을 던지며, 그 전에 작업이 완료되면 그 결과를 반환한다.
- `isDone()`: 연산이 완료되었는지의 여부를 반환한다. 작업이 완료되었다면 `true`, 그렇지 않다면 `false`를 반환한다.
- `cancel(boolean mayInterruptIfRunning)`: 연산을 취소한다. 매개 변수는 작업이 진행 중일 때 중단해도 되는지를 결정한다.
- `isCancelled()`: 작업이 취소되었는지의 여부를 반환한다. 작업이 취소되었다면 `true`, 그렇지 않다면 `false`를 반환한다.
## Future 사용 예시
#### 예시 1: `Future` 생성 및 사용
```java
Callable<Integer> task = () -> {
Thread.sleep(1000); // 1초동안 대기
return 123; // 결과 반환
};
FutureTask<Integer> future = new FutureTask<>(task);
new Thread(future).start(); // Future 작업 실행
// 다른 작업 ...
Integer result = future.get(); // 결과가 준비될 때까지 Blocking
System.out.println("Result: " + result);
```
#### 예시 2: `ExecutorService`와 `Future`를 이용해 비동기 작업을 실행하기
```java
// ExecutorService 생성
ExecutorService executor = Executors.newFixedThreadPool(10);
// 비동기 작업 제출
// ExecutorService의 submit 메소드는 Callable이나 Runnable 객체를 인수로 받아서 비동기적으로 실행하며, 결과를 Future 객체로 반환한다.
Future<Integer> future = executor.submit(() -> {
// 긴 작업 수행
Thread.sleep(1000);
return 123;
});
// 다른 작업 수행...
// 결과 가져오기
try {
Integer result = future.get(); // 결과를 가져온다. 필요한 경우에만 호출한다.
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
// 예외 처리
}
// ExecutorService 종료
executor.shutdown();
```
#### 예시3: `Future`에서 결과 가져오기
```java
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Integer> future = executorService.submit(() -> {
Thread.sleep(2000); // 임의의 긴 작업 수행
return 10;
});
try {
Integer result = future.get(); // 결과가 준비될 때까지 블로킹된다.
System.out.println(result); // 10
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
```
#### 예시 4: `Future`에서 타임아웃 설정하여 결과 가져오기
```java
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Integer> future = executorService.submit(() -> {
Thread.sleep(3000); // 임의의 긴 작업 수행
return 10;
});
try {
Integer result = future.get(2, TimeUnit.SECONDS); // 2초 후에 TimeoutException 발생
System.out.println(result);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
```
#### 예시 5: `Future` 작업 취소하기
```java
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Integer> future = executorService.submit(() -> {
Thread.sleep(3000); // 임의의 긴 작업 수행
return 10;
});
future.cancel(true); // 작업 취소. 작업이 진행 중이라도 중단한다.
try {
Integer result = future.get(); // CancellationException 발생
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
```
## Future의 장단점과 활용 상황
Java의 `Future` 인터페이스는 비동기 작업의 결과를 추상화하고 관리하는데 매우 유용한 도구다. 하지만 `Future`는 모든 상황에 적합한 도구는 아니다. 그렇기 때문에 `Future`의 장단점과 이를 활용하는 적절한 상황에 대해 이해하는 것이 중요하다.
- 장점
- 비동기 작업의 결과를 쉽게 관리할 수 있다.
- 작업 완료를 기다릴 필요 없이, 결과가 필요할 때 가져올 수 있다.
- `isDone()` 메소드를 통해 작업 완료를 확인할 수 있다.
- 단점
- 작업 완료 알림의 부재: Future는 작업이 완료되었는지 알려주는 메소드(`isDone()`)를 제공하지만, 이 메소드는 polling 방식으로 작동한다. 즉, 계속해서 메소드를 호출하여 작업 완료 여부를 확인해야 한다.
- 연산 결과를 가져올 때 블로킹된다: `get()` 메소드를 호출하면 결과가 준비될 때까지 현재 스레드가 블로킹된다. 이는 `get(long timeout, TimeUnit unit)` 메소드로 일부 해결할 수 있지만, 완벽한 해결책은 아니다.
### 활용 상황
`Future`는 비동기 작업의 결과를 관리하고, 그 결과를 필요로 하는 시점에서 쉽게 가져올 수 있어야 하는 경우에 사용된다. 하지만 작업 완료 알림이 필요하거나, 비동기 작업 간의 종속성을 관리해야 하는 경우에는 Java 8에서 도입된 `CompletableFuture`를 사용하는 것이 더 적절하다. `CompletableFuture`는 `Future`의 단점을 보완하며, 작업 완료 알림, 작업 체이닝, 예외 처리 등의 추가 기능을 제공한다.
Java의 `Future`는 비동기 작업의 결과를 처리하는 강력한 도구다. 하지만 `Future`만으로는 작업이 완료될 때까지 블로킹되거나, 작업의 완료를 주기적으로 폴링해야 하는 등의 단점이 있다. 이러한 문제를 해결하기 위해 Java 8에서는 `CompletableFuture`가 도입되었으며, 이는 `Future`의 기능을 향상시킨 버전이다. `CompletableFuture` 는 `Future`의 단점을 극복하고, 비동기 작업의 완료 알림이나 종속성 관리와 같은 추가적인 기능을 제공한다.
그럼에도 불구하고, `Future`는 여전히 유용하며, 병렬 프로그래밍을 할 때 알아두면 도움이 되는 개념이다.