동시에 여러 작업들을 실행시키는 메소드도 제공하고 있는데, 비동기(Asynchronous) 작업의 진행을 추적할 수 있도록 Future를 반환한다.
반환된 Future들은 모두 실행된 것이므로 반환된 isDone은 true이다.
하지만 작업들은 정상적으로 종료되었을 수도 있고, 예외에 의해 종료되었을 수도 있으므로 항상 성공한 것은 아니다.
이러한 ExecutorService가 갖는 비동기 작업을 위한 메서드들을 정리하면 다음과 같다.
submit
실행할 작업들을 추가하고, 작업의 상태와 결과를 포함하는 Future를 반환한다.
Future의 get을 호출하면 성공적으로 작업이 완료된 후 결과를 얻을 수 있다.
invokeAll
모든 결과가 나올 때 까지 대기하는 블로킹 방식의 요청한다.
동시에 주어진 작업들을 모두 실행하고, 전부 끝나면 각각의 상태와 결과를 갖는 List<Future>을 반환한다.
invokeAny
가장 빨리 실행된 결과가 나올 때 까지 대기하는 블로킹 방식의 요청한다.
동시에 주어진 작업들을 모두 실행하고, 가장 빨리 완료된 하나의 결과를 Future로 반환받는다.
ExecutorService의 구현체로는 AbstractExecutorService가 있는데, ExecutorService의 메서드들(submit, invokeAll, invokeAny)에 대한 기본 구현들을 제공한다.
invokeAll은 최대 쓰레드 풀의 크기만큼 작업을 동시에 실행시킨다.
그러므로 쓰레드가 충분하다면 동시에 실행되는 작업들 중에서 가장 오래 걸리는 작업만큼 시간이 소요된다.
하지만 만약 쓰레드가 부족하다면 대기되는 작업들이 발생하므로 가장 오래 걸리는 작업의 시간에 더해 추가 시간이 필요하다.
예시
Java
invokeAny는 가장 빨리 끝난 작업 결과만을 구하므로, 동시에 실행한 작업들 중에서 가장 짧게 걸리는 작업만큼 시간이 걸린다.
또한 가장 빠르게 처리된 작업 외의 나머지 작업들은 완료되지 않았으므로 cancel 처리되며, 작업이 진행되는 동안 작업들이 수정되면 결과가 정의되지 않는다.
Java
Synapse Map Insight
@Testvoidshutdown(){ExecutorService executorService =Executors.newFixedThreadPool(10);Runnable runnable =()->System.out.println("Thread: "+Thread.currentThread().getName()); executorService.execute(runnable);// shutdown 호출 executorService.shutdown();// shutdown 호출 이후에는 새로운 작업들을 받을 수 없음, 에러 발생RejectedExecutionException result =assertThrows(RejectedExecutionException.class,()-> executorService.execute(runnable));assertThat(result).isInstanceOf(RejectedExecutionException.class);}