스프링 스터디 (인프런)/더 자바 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 결과가 출력된다.