-
CompletableFuture (3) - Callable 과 Future프로그래밍/Java 2022. 6. 14. 15:18
Thread는 Runnable과 Callable의 구현된 함수를 수행한다는 공통점이 있지만, 다음과 같은 차이점이 있다.
- Runnable: 어떤 객체도 리턴하지 않습니다. Exception을 발생시키지 않습니다.
- Callable: 특정 타입의 객체를 리턴합니다. Exception을 발생킬 수 있습니다.
Callable
- 이전까지 사용했던 Runnable과 유사하지만 작업의 결과(return) 를 받을 수 있다.
Future
- Future 는 자바 1.5 에 등장한 비동기 계산 결과를 나타내는 인터페이스
- 비동기적인 작업의 현재 상태를 조회하거나 결과를 가져올 수 있다.
- Future를 이용하면 멀티쓰레드 환경에서 처리된 어떤 데이터를 다른 쓰레드에 전달할 수 있다.
- Future 내부적으로 Thread-Safe 하도록 구현되었기 때문에 synchronized block을 사용하지 않아도 된다.
- 비동기적인 작업을 수행?
- 현재 진행하고 있는 Thread 가 아닌 별도의 Thread 에서 작업을 수행하는 것을 말한다.
- 같은 Thread 에서 메서드를 호출할 때는 리턴 값을 받지만, 비동기적으로 작업을 수행할 때는 리턴 값을 전달받을 수 있는 무언가의 interface 가 필요한데 Future 가 그 역할을 한다.
Callable 과 Future 실습하기
결과를 가져오기 get()
- 블록킹 콜이다.
- 타임아웃(최대한으로 기다릴 시간)을 설정할 수 있다.
작업 상태 확인하기 isDone()
- 완료 했으면 true 아니면 false를 리턴한다.
작업 취소하기 cancel()
- 취소 했으면 true 못했으면 false를 리턴한다.
- parameter로 true를 전달하면 현재 진행중인 쓰레드를 interrupt하고 그러지 않으면 현재 진행중인 작업이 끝날때까지 기다린다.
package com.example.reactivestreamstoby; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class Main { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); Callable<String> hello = () -> { Thread.sleep(1000L); return "Hello"; }; System.out.println("start"); // submit 시, Runnable 도 동일하게 Future 로 받을 수 있었다. // Callable 이 리턴하는 타입의 Future 를 받을 수 가 있게된다. Future<String> helloFuture = executorService.submit(hello); // 상태를 알고싶을때 상태에 따라 true/false 반환 System.out.println(helloFuture.isDone()); // Future 를 가지고 submit 이 만들어주는 값을 get 을 통해 꺼낼 수 있다. // get 이전까지는 코드가 계속해서 실행이 되지만, get 을 만나는 순간 멈춰서 결과값을 가져올때까지 기다린다. (블록킹 콜) helloFuture.get(); // 작업 취소 기능, get() 을 할 수 없다. helloFuture.cancel(false); System.out.println("end"); executorService.shutdown(); } }
여러 작업 동시에 실행하기 invokeAll()
- 동시에 실행한 작업중에 제일 오래걸리는 작업 만큼 시간이 걸린다.
package com.example.reactivestreamstoby; import java.util.Arrays; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Main { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); Callable<String> hello = () -> { Thread.sleep(1000L); return "hello"; }; Callable<String> java = () -> { Thread.sleep(2000L); return "java"; }; Callable<String> hyokeun = () -> { Thread.sleep(3000L); return "hyokeun"; }; // invokeAll 은 1초, 2초, 3초 로 준 애들이 다 끝날때까지 기다린다. 즉, 자바가 끝날때까지 (3초) 기다리는것 List<Future<String>> futures = executorService.invokeAll(Arrays.asList(hello, java, hyokeun)); for (Future<String> f : futures) { System.out.println(f.get()); } executorService.shutdown(); } }
여러 작업 중에 하나라도 먼저 응답이 오면 끝내기 invokeAny()
- 동시에 실행한 작업중에 제일 짧게 걸리는 작업 만큼 시간이 걸린다.
- 블록킹 콜이다.
package com.example.reactivestreamstoby; import java.util.Arrays; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Main { public static void main(String[] args) throws ExecutionException, InterruptedException { // 싱글쓰레드로 주면 맨 처음것만 나온다. 가장 먼저 처리되고 나머지는 큐에서 대기하고 있기 때문이다. ExecutorService executorService = Executors.newFixedThreadPool(4); Callable<String> hello = () -> { Thread.sleep(5000L); return "hello"; }; Callable<String> java = () -> { Thread.sleep(2000L); return "java"; }; Callable<String> hyokeun = () -> { Thread.sleep(3000L); return "hyokeun"; }; // 그런데 특정 서버 3대를 두고 모두 같은 값을 가져와야한다면 3대 모두를 기다릴 필요가 있을까? -> 이 경우에 해당되는데 InvokeAny // 여기선 가장 빠른 java (2초) 가 출력 String s = executorService.invokeAny(Arrays.asList(hello, java, hyokeun)); System.out.println(s); executorService.shutdown(); } }
참고
인프런 - 더 자바, Java8 (백기선)
'프로그래밍 > Java' 카테고리의 다른 글
Java Virtual Thread (2), Thread와 Virtual Thread (0) 2024.06.22 Java Virtual Thread (1) (1) 2024.06.16 인터페이스 default 메소드와 static 메소드 (0) 2022.06.09 메소드 레퍼런스 (0) 2022.06.08 자바에서 제공하는 함수형 인터페이스 (0) 2022.06.07