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 |