스프링 스터디 (인프런)/더 자바 8
섹션6. Callable과 Future
백엔드 개발자
2023. 5. 14. 10:36
callable은 Runnable과 유사하지만 작업 결과를 리턴할 수 있다.
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Callable<String> hello = () -> {
Thread.sleep(2000L);
return "Hello";
};
Future<String> submit = executorService.submit(hello);
System.out.println("Started! ");
submit.get();
System.out.println("End!");
executorService.shutdown();
}
submit.get을 하게 되면 Callable을 기다린 후에 그다음 동작을 진행한다.
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Callable<String> hello = () -> {
Thread.sleep(2000L);
return "Hello";
};
Future<String> helloFuture = executorService.submit(hello);
System.out.println(helloFuture.isDone());
System.out.println("Started! ");
helloFuture.get();
System.out.println(helloFuture.isDone());
System.out.println("End!");
executorService.shutdown();
}
isDone을 사용하면 Callable객체의 실행여부를 확인할 수 있다.
helloFuture.get() 전 시점에서는 아직 Callable 객체가 실행되지 않았으니 false를 출력하고,
그 뒤에는 true를 출력한다.
ExecutorService executorService = Executors.newSingleThreadExecutor();
Callable<String> hello = () -> {
Thread.sleep(2000L);
return "Hello";
};
Future<String> helloFuture = executorService.submit(hello);
System.out.println(helloFuture.isDone());
System.out.println("Started! ");
helloFuture.cancel(true);
//helloFuture.get();
System.out.println(helloFuture.isDone());
System.out.println("End!");
executorService.shutdown();
Cancel을 사용하면 진행중인 작업을 종료한다. 내부값을 true로 주면 현재 진행중인 작업을 멈추고 종료.
false면 기다렸다가 종료한다.
그 뒤에 다시 get()을 해도 이미 취소된 작업이기 때문에 에러가 발생한다.
invokeAll(모든 결과를 다 기다려야 하는 경우)
invokeAll은 전달받은 파라미터 쓰레드들이 전부 끝날때까지 기다린다. 그 후 3개의 결과를 전부 가져온다.
invokeAny(다 같은 결과를 요청하고, 선착순으로 받기를 원하는 상황)
invokeAny를 사용하면 파라미터 쓰레드중 가장 빨리 응답받은 값을 리턴한다.
영상속 스레드 관련 예외
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(4);
Callable<String> hello = () -> {
Thread.sleep(2000L);
return "Hello";
};
Callable<String> java = () -> {
Thread.sleep(3000L);
return "Java";
};
Callable<String> keesun = () -> {
Thread.sleep(1000L);
return "keesun";
};
String s = executorService.invokeAny(Arrays.asList(hello, java, keesun));
System.out.println(s);
executorService.shutdown();
}
ExecutorService를 newSingleThreadExecutor or newFixedThreadPool(2이하)로 설정했을 경우,
keesun이 1초임에도 불구하고 Hello가 출력된다.
그 이유는 스레드풀이 파라미터 개수보다 적어서 가장 먼저들어온 Hello,java중 Hello가 더 먼저들어왔기 때문이다.
newFixedThreadPool(3~...)으로 설정해야 원하는 keesun 결과가 출력된다.