티스토리 뷰

CompletableFuture를 알기 전에 Concurrent 프로그래밍을 꼭 알아야 한다.

Callable과 Future를 알아보자.

Callable

Runnable과 다르게 작업의 결과를 리턴할 수 있다.

Future

비동기적인 작업의 현재 상태를 조회하거나 결과를 가져올 수 있다.

import java.util.concurrent.*;

import static java.lang.Thread.*;

public class App {
    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();
    }
}

위 코드처럼 get 메서드로 결과를 가져올 수 있다.

get은 블록킹 콜이다.

  • Started!가 출력되고 Callable의 hello가 처리된 후 End가 출력되는 것을 확인할 수 있다.

작업 상태 확인할 때에는 isDone() 메서드를 사용한다.

완료했으면 true 아니면 false를 리턴한다.

import java.util.concurrent.*;

import static java.lang.Thread.*;

public class App {
    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!");

        System.out.println(submit.isDone());
        submit.get(); // 블로킹 콜

        System.out.println("End");
        System.out.println(submit.isDone());
        executorService.shutdown();
    }
}

작업을 취소할 때에는 cancel() 메서드를 사용한다.

파라미터로 true를 전달하면 현재 진행중인 쓰레드를 interrupt하고 그렇지 않으면 현재 진행중인 작업이 끝날 때까지 기다린다.

⇒ 마치 shutdown과 shutdownNow 같다.

import java.util.concurrent.*;

import static java.lang.Thread.*;

public class App {
    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.cancel(true);
        System.out.println(submit.isDone());
        submit.get(); // 블로킹 콜

        System.out.println("End");
        System.out.println(submit.isDone());
        executorService.shutdown();
    }
}

다음 코드도 살펴보자.

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;

public class App {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        Callable<String> hello = () -> {
            Thread.sleep(2000L);
            return "Hello";
        };

        Callable<String> java = () -> {
            Thread.sleep(3000L);
            return "Java";
        };

        Callable<String> eric = () -> {
            Thread.sleep(1000L);
            return "Eric";
        };

        List<Future<String>> futures = executorService.invokeAll(Arrays.asList(hello, java, eric));
        for(Future<String> future : futures) {
            System.out.println(future.get());
        }

        executorService.shutdown();
    }
}

invokeAll을 통해 여러 작업을 동시에 실행시킬 수 있다.

위 코드를 실행시켜보면 Hello와 Java, Eric이 동시에 출력된다.

그 이유는 동시에 실행한 작업 중에 제일 오래 걸리는 작업 만큼 시간이 걸리기 때문이다.

🤔 3개의 정보를 모두 가져와야 할 경우에는 invokeAll을 사용하겠지만 3개 중 하나만 가져와도 된다면?

 

이 때에는 바로 invokeAny() 메서드를 사용한다.

import java.util.Arrays;
import java.util.concurrent.*;

public class App {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        Callable<String> hello = () -> {
            Thread.sleep(2000L);
            return "Hello";
        };

        Callable<String> java = () -> {
            Thread.sleep(3000L);
            return "Java";
        };

        Callable<String> eric = () -> {
            Thread.sleep(1000L);
            return "Eric";
        };

        String s = executorService.invokeAny(Arrays.asList(hello, java, eric));
        System.out.println(s);

        executorService.shutdown();
    }
}

이 때에는 newFixedThreadPool을 3개로 지정해서 사용해야 테스트가 가능하다.

이렇게 되면 Eric이 출력된다.

'JAVA' 카테고리의 다른 글

오브젝트의 동일성과 동등성  (0) 2022.07.10
방어적 복사  (0) 2022.05.01
java에서 멀티쓰레드 [2] Executors와 ExecutorService  (0) 2022.02.07
java에서 멀티쓰레드 [1] Thread와 Runnable  (0) 2022.02.07
Consumer  (0) 2022.02.04
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함