210 lines
8.8 KiB
Markdown
210 lines
8.8 KiB
Markdown
### 자바의 `Runnable`, `Callable`, `Future`, `CompletableFuture`에 대한 설명
|
|
|
|
자바에서 멀티스레드 프로그래밍을 지원하는 주요 인터페이스와 클래스는 `Runnable`, `Callable`, `Future`, 그리고 `CompletableFuture`입니다. 이들은 작업을 정의하고, 실행하며, 결과를 처리하는 데 사용됩니다. 아래에서 각 클래스와 관련 메서드를 표로 정리하고, 예시를 통해 사용 방법을 설명하겠습니다.
|
|
|
|
---
|
|
|
|
### 관련 클래스 및 메서드 표
|
|
|
|
#### `Runnable` 인터페이스
|
|
| 메서드명 | 반환 타입 | 설명 |
|
|
|-----------------|-----------|---------------------------------------------------|
|
|
| `run()` | `void` | 스레드가 실행할 작업을 정의 (추상 메서드) |
|
|
|
|
#### `Callable<V>` 인터페이스
|
|
| 메서드명 | 반환 타입 | 설명 |
|
|
|-----------------|-----------|---------------------------------------------------|
|
|
| `call()` | `V` | 결과를 반환하며 예외를 던질 수 있는 작업 정의 |
|
|
|
|
#### `Future<V>` 인터페이스
|
|
| 메서드명 | 반환 타입 | 설명 |
|
|
|-------------------------|-----------|---------------------------------------------------|
|
|
| `get()` | `V` | 작업 결과를 반환 (완료될 때까지 대기) |
|
|
| `get(long, TimeUnit)` | `V` | 지정된 시간 동안 대기 후 결과 반환 |
|
|
| `cancel(boolean)` | `boolean` | 작업을 취소 시도하고 성공 여부 반환 |
|
|
| `isDone()` | `boolean` | 작업이 완료되었는지 확인 |
|
|
| `isCancelled()` | `boolean` | 작업이 취소되었는지 확인 |
|
|
|
|
#### `CompletableFuture<V>` 클래스
|
|
| 메서드명 | 반환 타입 | 설명 |
|
|
|-----------------------------------|-------------------------|----------------------------------------------------------------------|
|
|
| `runAsync(Runnable)` | `CompletableFuture<Void>` | 비동기적으로 `Runnable` 실행 |
|
|
| `supplyAsync(Supplier<V>)` | `CompletableFuture<V>` | 비동기적으로 값을 제공하는 작업 실행 |
|
|
| `thenApply(Function<T, U>)` | `CompletableFuture<U>` | 이전 작업의 결과에 함수를 적용하여 변환된 결과 반환 |
|
|
| `thenAccept(Consumer<T>)` | `CompletableFuture<Void>` | 결과에 대한 소비 동작 수행 |
|
|
| `thenRun(Runnable)` | `CompletableFuture<Void>` | 결과와 상관없이 후속 작업 실행 |
|
|
| `exceptionally(Function<Throwable, T>)` | `CompletableFuture<T>` | 예외 발생 시 처리 로직 정의 |
|
|
| `complete(V)` | `boolean` | 작업을 수동으로 완료하고 결과 설정 |
|
|
| `join()` | `V` | 작업 완료를 기다리고 결과 반환 (스레드 풀에서 사용 시 주의) |
|
|
| `allOf(CompletableFuture<?>...)` | `CompletableFuture<Void>` | 여러 `CompletableFuture`가 모두 완료될 때까지 대기 |
|
|
| `anyOf(CompletableFuture<?>...)` | `CompletableFuture<Object>` | 여러 `CompletableFuture` 중 하나가 완료되면 결과 반환 |
|
|
|
|
---
|
|
|
|
### 설명 및 예시
|
|
|
|
이들 클래스는 멀티스레드 작업의 정의와 실행, 결과 처리를 다룹니다. `Runnable`은 기본적인 작업 단위이고, `Callable`은 결과를 반환하며, `Future`는 결과를 추적하고, `CompletableFuture`는 비동기 작업의 조합과 예외 처리를 지원합니다.
|
|
|
|
#### 1. `Runnable`: 기본 작업 정의
|
|
`Runnable`은 결과를 반환하지 않는 간단한 작업을 정의합니다.
|
|
|
|
```java
|
|
public class RunnableExample {
|
|
public static void main(String[] args) {
|
|
Runnable task = () -> {
|
|
System.out.println("Runnable 작업 실행: " + Thread.currentThread().getName());
|
|
};
|
|
|
|
Thread thread = new Thread(task);
|
|
thread.start();
|
|
}
|
|
}
|
|
```
|
|
- **출력 예시**:
|
|
```
|
|
Runnable 작업 실행: Thread-0
|
|
```
|
|
|
|
#### 2. `Callable`과 `Future`: 결과 반환
|
|
`Callable`은 값을 반환하며, `Future`로 결과를 받습니다.
|
|
|
|
```java
|
|
import java.util.concurrent.*;
|
|
|
|
public class CallableFutureExample {
|
|
public static void main(String[] args) throws Exception {
|
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
|
|
|
Callable<String> task = () -> {
|
|
Thread.sleep(1000);
|
|
return "Callable 작업 완료";
|
|
};
|
|
|
|
Future<String> future = executor.submit(task);
|
|
System.out.println("작업 제출 완료");
|
|
|
|
String result = future.get(); // 완료 대기
|
|
System.out.println(result);
|
|
|
|
executor.shutdown();
|
|
}
|
|
}
|
|
```
|
|
- **출력 예시**:
|
|
```
|
|
작업 제출 완료
|
|
(1초 후)
|
|
Callable 작업 완료
|
|
```
|
|
- **설명**: `Future.get()`은 작업이 끝날 때까지 대기하며 결과를 반환.
|
|
|
|
#### 3. `CompletableFuture`: 비동기 작업 조합
|
|
`CompletableFuture`는 비동기 작업을 연결하고 결과를 처리하는 데 유용합니다.
|
|
|
|
```java
|
|
import java.util.concurrent.*;
|
|
|
|
public class CompletableFutureExample {
|
|
public static void main(String[] args) throws Exception {
|
|
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
|
|
try {
|
|
Thread.sleep(1000);
|
|
} catch (InterruptedException e) {
|
|
e.printStackTrace();
|
|
}
|
|
return "비동기 결과";
|
|
}).thenApply(result -> result + " 처리됨")
|
|
.thenApply(result -> result.toUpperCase());
|
|
|
|
String result = future.get();
|
|
System.out.println(result);
|
|
}
|
|
}
|
|
```
|
|
- **출력 예시**:
|
|
```
|
|
(1초 후)
|
|
비동기 결과 처리됨
|
|
```
|
|
- **설명**: `supplyAsync`로 값을 생성하고, `thenApply`로 결과를 변환.
|
|
|
|
#### 4. `CompletableFuture` 예외 처리 및 조합
|
|
예외 처리와 여러 작업의 동시 실행을 다룹니다.
|
|
|
|
```java
|
|
import java.util.concurrent.*;
|
|
|
|
public class CompletableFutureAdvancedExample {
|
|
public static void main(String[] args) throws Exception {
|
|
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
|
|
try {
|
|
Thread.sleep(500);
|
|
} catch (InterruptedException e) {
|
|
e.printStackTrace();
|
|
}
|
|
return "작업 1";
|
|
});
|
|
|
|
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
|
|
throw new RuntimeException("작업 2 실패");
|
|
}).exceptionally(throwable -> "복구: " + throwable.getMessage());
|
|
|
|
CompletableFuture<Void> all = CompletableFuture.allOf(future1, future2);
|
|
all.thenRun(() -> {
|
|
try {
|
|
System.out.println(future1.get() + " & " + future2.get());
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
}).join(); // 모든 작업 완료 대기
|
|
}
|
|
}
|
|
```
|
|
- **출력 예시**:
|
|
```
|
|
작업 1 & 복구: java.lang.RuntimeException: 작업 2 실패
|
|
```
|
|
- **설명**: `exceptionally`로 예외를 처리하고, `allOf`로 여러 작업을 조합.
|
|
|
|
#### 5. `CompletableFuture`로 수동 완료
|
|
`complete`를 사용해 작업을 수동으로 완료할 수 있습니다.
|
|
|
|
```java
|
|
import java.util.concurrent.*;
|
|
|
|
public class ManualCompleteExample {
|
|
public static void main(String[] args) {
|
|
CompletableFuture<String> future = new CompletableFuture<>();
|
|
|
|
new Thread(() -> {
|
|
try {
|
|
Thread.sleep(1000);
|
|
future.complete("수동 완료");
|
|
} catch (InterruptedException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}).start();
|
|
|
|
String result = future.join();
|
|
System.out.println(result);
|
|
}
|
|
}
|
|
```
|
|
- **출력 예시**:
|
|
```
|
|
(1초 후)
|
|
수동 완료
|
|
```
|
|
|
|
---
|
|
|
|
### 비교와 특징
|
|
- **`Runnable`**: 결과 없음, 단순 작업 실행.
|
|
- **`Callable`**: 결과 반환, `Future`와 함께 사용.
|
|
- **`Future`**: 비동기 작업 상태 추적, 블록킹 방식.
|
|
- **`CompletableFuture`**: 비동기 작업 조합, 예외 처리, 논블록킹 지원.
|
|
|
|
---
|
|
|
|
### 결론
|
|
`Runnable`과 `Callable`은 작업을 정의하고, `Future`는 결과를 추적하며, `CompletableFuture`는 복잡한 비동기 작업을 유연하게 처리합니다. 상황에 따라 적합한 클래스를 선택해 사용하면 효율적인 멀티스레드 프로그래밍이 가능합니다. 위 예시를 참고하여 실제 애플리케이션에 적용해 보세요! |