반응형
Callable
- Runnable과 유사하지만 작업의 결과를 받을 수 있다.
- Runnable은 리턴 값이 없기 때문에 쓰레드가 수행한 작업의 결과를 이용해서 어떠한 처리를 할 수 없다.
Future
- 비동기적인 작업의 현재 상태를 조회하거나 결과를 가져올 수 있다.
결과를 가져오기 get()
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<String> helloFuture = executorService.submit(() -> {
Thread.sleep(2000L);
return "Callable";
});
System.out.println("Hello");
String result = helloFuture.get();
System.out.println(result);
executorService.shutdown();
- 블록킹 콜이다.
- 결과 값을 가져올 때까지 해당 위치에서 대기
- 타임아웃(최대한으로 기다릴 시간)을 설정할 수 있다.
작업 상태 확인하기 isDone()
- 완료 했으면 true 아니면 false를 리턴한다.
작업 취소하기 cancel()
- 취소 했으면 true 못했으면 false를 리턴한다.
- parameter로 true를 전달하면 현재 진행중인 쓰레드를 interrupt하고 그러지 않으면 현재 진행중인 작업이 끝날때까지 기다린다.
여러 작업 동시에 실행하기 invokeAll()
- 동시에 실행한 작업 중에 제일 오래 걸리는 작업 만큼 시간이 걸린다.
- Dev와 Hello가 먼저 작업이 끝났더라도 제일 오래 걸리는 작업인 Java가 끝나야 값을 가져올 수 있다.
여러 작업 중에 하나라도 먼저 응답이 오면 끝내기 invokeAny()
- 동시에 실행한 작업 중에 제일 짧게 걸리는 작업 만큼 시간이 걸린다.
- 제일 짧게 걸리는 Server2의 응답이 오면 값을 가져올 수 있다.
- 블록킹 콜이다.
- 결과 값을 가져올 때까지 해당 위치에서 대기
Callable, Future 예제
public class Main {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
Callable<String> hello = () -> {
System.out.println("Callable hello Start!");
Thread.sleep(2000L);
return "Hello";
};
Callable<String> java = () -> {
Thread.sleep(3000L);
return "Java";
};
//현재 Executor 쓰레드가 2개이기 때문에 Blocking Queue에서 대기(hello가 완료되어야 작업 수행 가능)
Callable<String> dev = () -> {
Thread.sleep(1000L);
return "Dev";
};
/*
invokeAll() : Callable을 뭉쳐서 여러 작업을 동시에 수행할 수 있다.
- 작업이 제일 오래걸리는 쓰레드가 완료되어야만 값을 가져올 수 있다.
*/
try {
List<Future<String>> futures = executorService.invokeAll(Arrays.asList(hello, java, dev));
System.out.println("-------------------");
for(Future<String> f : futures) {
System.out.println(f.get());
}
System.out.println("-------------------");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
/*
invokeAny() : Callable을 뭉쳐서 여러 작업을 동시에 수행할 수 있다.
- 작업이 제일 빨리끝나는 쓰레드의 응답이 오면 값을 가져올 수 있다.
- 블로킹 콜이다.
*/
try {
System.out.println("-------------------");
String s = executorService.invokeAny(Arrays.asList(hello, java, dev));
System.out.println(s);
System.out.println("-------------------");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
//Callable이 리턴하는 타입의 Future를 얻을 수 있다.
Future<String> helloFuture = executorService.submit(hello);
System.out.println("#######################");
System.out.println(helloFuture.isDone()); //수행중인 작업이 끝났으면 true, 아니면 false
System.out.println("Main Started!");
/*
현재 진행중인 작업을 interrupt 하면서 종료
*/
//helloFuture.cancel(true);
/*
현재 진행중인 작업을 기다리고 종료(==graceful)
- 작업 완료를 기다린다고해도 cancel이 호출되면 Future에서 값을 꺼내는 것이 불가능하다.
-> 이미 취소시킨 작업에서 꺼내려고하면 CancellationException 에러 발생
- cancel을 하면 상태(isDone)는 무조건 true가 된다.
-> 이 때의 true는 작업이 완료되었으니 값을 꺼낼 수 있다는 의미가 아니다.
-> cancel 했기 때문에 종료된 것이다.
*/
//helloFuture.cancel(false);
try {
/*
get() 이전 까지는 코드는 계속 실행된다.
get()을 만나면 결과 값을 가져올 때까지 대기(Blocking Call)
*/
String s = helloFuture.get();//get()을 통해 Future의 값을 꺼낸다.
System.out.println(helloFuture.isDone()); //작업이 끝났으면 true, 아니면 false
System.out.println(s);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println("Main End");
executorService.shutdown();
}
}
반응형
'Java > 기본' 카테고리의 다른 글
자바 애노테이션(Java Annotation)의 변화 (0) | 2021.07.05 |
---|---|
자바 동시성(Java Concurrent) - 4 (CompletableFuture) (0) | 2021.07.05 |
자바 동시성(Java Concurrent) - 2 (Executors) (0) | 2021.07.04 |
자바 동시성(Java Concurrent) - 1 (Thread) (0) | 2021.07.02 |
자바(Java) Date-Time API - 2 (Date-Time API 활용) (0) | 2021.07.01 |
[참고자료]
더 자바, Java 8, 백기선