ExecutorService 인터페이스는 Executor의 확장된 버전입니다. 스레드의 생명 주기에 대한 메서드가 있어서 스레드 관리를 훨씬 더 편리하게 제공합니다.
ExecutorService 메서드
- shutdown : 이전에 제출된 작업은 순차적으로 실행되면서 종료됩니다. 새로운 작업은 허용하지 않습니다. 이전에 제출된 작업이 실행은 되지만 완료할 때까지는 기다리지 않습니다.
- shutdownNow : 이전에 제출된 작업이 실행되지 않고 바로 종료되면서 가지고 있던 작업 목록을 반환합니다. shoutdown과 마찬가지로 실행 중인 작업이 종료될 때까지 기다리지 않습니다.
- isShutdown : ExecutorService가 shutdown 상태이면 true 아니면 false를 반환합니다.
- isTerminated : shutdown 상태에서 모든 작업이 완료되면 true 아니면 false를 반환합니다.
- awaitTermination : ExecutorService가 종료될때까지 대기하거나 특정 시간동안 대기하는 기능을 제공합니다.
- submit(Callable) : 작업의 결과를 알고 싶을때 execute 메서드 대신에 사용합니다. Future 인스턴스를 반환하는데 get 메서드를 사용하여 작업의 결과를 알 수 있습니다.
- submit(Runnable, T) : 작업의 결과를 알 수 있는 Future를 반환합니다. get 메서드를 사용하여 2번째 파라미터로 넣은 결과값을 반환합니다.
- submit(Runnalbe) : 작업의 결과를 알 수 있는 Future를 반환합니다. get 메서드를 사용하여 결과가 성공적이면 null을 반환합니다.
- invokeAll(Collection) : 모든 작업이 완료될 때 그 상태와 결과를 담고 있는 Future들의 목록을 반환합니다. Future 인스턴스에 isDone 메서드는 작업이 완료되었는지 여부입니다.
- invokeAll(Collection, long, TimeUnit) : 모든 작업이 완료되거나 제한 시간이 만료되면 그 상태와 결과를 담고 있는 Future들의 목록을 반환합니다. 반환 시 완료되지 않은 작업은 취소됩니다.
- invokeAny(Collection) : 주어진 작업들을 실행하고 성공적으로 완료된 작업이 있으면 나머지 작업들은 취소됩니다.
- invokeAny(Collection, long, TimeUnit) : 주어진 시간이 경과하기 전에 작업이 완료되면 나머지 작업들은 취소됩니다.
ExecutorService shutdown 예시
public class ShutdownExample {
public static void main(String[] args) {
int i = 1;
boolean cmd = true;
ExecutorService executorService = Executors.newFixedThreadPool(1);
Runnable task1 = () -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
};
while(i < 10) {
try {
executorService.execute(task1);
} catch(RejectedExecutionException e) {
System.out.println(e.getMessage());
}
i++;
if(i > 5 && cmd) {
cmd = false;
System.out.println("shutdown 호출" );
executorService.shutdown();
}
}
}
}
i가 5가 넘어가면 shutdown이 호출되면서 shutdown 상태일때 execute를 실행하기 때문에 RejectedExecutionException 메시지가 나옵니다. 그리고 1초 간격으로 5번 task1이 실행됩니다.
ExecutorService shutdownNow 예시
public class ShutdownNowExample {
public static void main(String[] args) {
int i = 1;
boolean cmd = true;
ExecutorService executorService = Executors.newFixedThreadPool(1);
Runnable task1 = () -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
System.out.println(Thread.currentThread().getName());
};
while(i < 10) {
try {
executorService.execute(task1);
} catch(RejectedExecutionException e) {
System.out.println(e.getMessage());
}
i++;
if(i > 5 && cmd) {
cmd = false;
System.out.println("shutdown 호출" );
executorService.shutdownNow();
}
}
}
}
i가 5가 넘어가면 shutdown이 호출되면서 shutdown 상태일때 execute를 실행하기 때문에 RejectedExecutionException 메시지가 나옵니다. 그리고 실행중인 작업은 반환이 되고 대기 중인 작업들은 종료됩니다.
ExecutorService isShutdown & isTerminated 예시
public class IsShutdownExample {
public static void main(String[] args) throws InterruptedException {
int i = 1;
boolean cmd = true;
ExecutorService executorService = Executors.newFixedThreadPool(1);
Runnable task1 = () -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
};
while(i < 10) {
try {
executorService.execute(task1);
} catch(RejectedExecutionException e) {
System.out.println(e.getMessage());
}
i++;
if(i > 5 && cmd) {
cmd = false;
System.out.println("shutdown 호출" );
executorService.shutdown();
System.out.println("isShutdown:" + executorService.isShutdown());
System.out.println("isTerminated:" + executorService.isTerminated());
}
}
Thread.sleep(6000);
System.out.println("isTerminated:" + executorService.isTerminated());
}
}
shutdown이 호출되고 나서 isShutdown은 true가 나오지만 작업이 완료가 되지는 않았기때문에 isTerminated는 false가 나옵니다. 6초 뒤에 isTerminated를 실행하면 모든 작업이 끝난 뒤라서 true가 나옵니다.
ExecutorService awaitTermination 예시
public class AwaitTerminationExample {
public static void main(String[] args) throws InterruptedException {
int i = 1;
boolean cmd = true;
ExecutorService executorService = Executors.newFixedThreadPool(1);
Runnable task1 = () -> {
System.out.println(Thread.currentThread().getName());
};
while(i < 10) {
try {
executorService.execute(task1);
} catch(RejectedExecutionException e) {
System.out.println(e.getMessage());
}
i++;
if(i > 5 && cmd) {
cmd = false;
System.out.println("shutdown 호출" );
executorService.awaitTermination(5, TimeUnit.SECONDS);
}
}
}
}
task1이 실행되다가 i가 5가 넘어가면 작업이 아직 종료되지 않았기 때문에 awaitTermination 5초뒤에 넘어가서 실행됩니다.
만약 shutdown을 하고 awaitTermination를 하면 종료가 되었기 때문에 바로 넘어갑니다.
ExecutorService submit 예시
public class SubmitExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(1);
Callable<String> task1 = () -> {
System.out.println(Thread.currentThread().getName());
return "hello";
};
Future<String> result1 = executorService.submit(task1);
System.out.println(result1.get());
Runnable task2 = () -> System.out.println(Thread.currentThread().getName());
String runResult = "hi";
Future<String> result2 = executorService.submit(task2, runResult);
System.out.println(result2.get());
Future<?> result3 = executorService.submit(task2);
System.out.println(result3.get());
executorService.shutdown();
}
}
result1은 hello가 리턴되고 result2은 hi가 리턴되고 result3는 null이 리턴이 됩니다.
ExecutorService invokeAll & invokeAny 예시
public class InvokeExample {
public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
ExecutorService executorService = Executors.newFixedThreadPool(1);
Callable<String> task = () -> {
Thread.sleep(1000);
return "hello";
};
List<Callable> list = new ArrayList<>();
for(int j = 0; j < 5 ; j++) {
list.add(task);
}
List<Future<String>> result1 = executorService.invokeAll((Collection) list);
for(Future<String> item : result1) {
System.out.println("result1:" + item.get());
}
List<Future<String>> result2 = executorService.invokeAll((Collection) list, 3, TimeUnit.SECONDS);
for(Future<String> item : result2) {
try {
System.out.println("result2:" + item.get());
} catch(CancellationException e) {
}
}
String result3 = (String) executorService.invokeAny((Collection) list);
System.out.println("result3:" + result3);
String result4 = (String) executorService.invokeAny((Collection) list, 3, TimeUnit.SECONDS);
System.out.println("result4:" + result4);
executorService.shutdown();
}
}
result1에서는 invokeAll이기 때문에 모든 작업이 완료된 뒤 반환이 되기 때문에 5초가 걸립니다.
result2에서는 3초 제한이 있는 invokeAll이기 때문에 3초가 되면 나머지 작업은 취소하고 반환됩니다.
result3에서는 invokeAny이기 때문에 하나의 성공된 작업이 나오면 그 작업만 반환됩니다.
result4에서는 3초 제한이 있는 invokeAny이기 때문에 1초뒤 성공된 작업이 나오면 그 작업만 반환됩니다.
'JAVA > 스레드' 카테고리의 다른 글
[JAVA] ScheduledExecutorService 인터페이스 (0) | 2023.10.18 |
---|---|
[JAVA] Executors 클래스 (0) | 2023.10.17 |
[JAVA] Executor 인터페이스 (0) | 2023.10.10 |
[JAVA] 스레드 풀의 개념과 필요성 (0) | 2023.10.06 |
[JAVA] ReentrantLock 활용 Condition 인터페이스 (1) | 2023.10.04 |