Concurrency
ExecutorService: submitした例外はFutureで観測する
submitしたタスクの例外は呼び出し元へ直ちに投げられず、Future.getでExecutionExceptionとして観測します。
SourceSubmittedTasks.java
Java 21
package examples.executor;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
public final class SubmittedTasks {
private SubmittedTasks() {}
public static Future<String> submitFailing(ExecutorService executor) {
Callable<String> task = () -> { throw new IllegalArgumentException("invalid task"); };
return executor.submit(task);
}
}TestSubmittedTasksTest.java
Java 21
package examples.executor;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import org.junit.jupiter.api.Test;
class SubmittedTasksTest {
@Test
void submitしたタスクの例外はFutureのgetでExecutionExceptionとして観測する() {
try (var executor = Executors.newSingleThreadExecutor()) {
var future = SubmittedTasks.submitFailing(executor);
var exception = assertThrows(ExecutionException.class, future::get);
assertEquals(IllegalArgumentException.class, exception.getCause().getClass());
}
}
}01Assertion
このテストで確認できること
- submitは失敗するCallableのFutureを返す
- getは原因例外をcauseに持つExecutionExceptionを送出する
ExecutorServiceへ渡した仕事の失敗はFutureを回収しない限り見落とせます。タスクの監視・失敗処理・shutdownを呼び出し側の契約に含めます。
OBSERVED RESULT
expected exception: Future.get → ExecutionException
expected cause: IllegalArgumentException