런타임노트

[Java] ExecutorService, Executors 본문

JAVA

[Java] ExecutorService, Executors

D269 2023. 8. 23. 17:34
728x90

 

업무 중에 다른 서버 두 군데로 명령어를 동시에 보내야 하는 일이 생겼다.

폭풍 구글링,,

 

 

1. ExecutorService ?

- 병렬 작업을 할 때 여러 작업을 효율적으로 처리하기 위해 제공되는 java 라이브러리

- 작업(Runnable, Callable) 등록을 위한 인터페이스.

- 각기 다른 쓰레드를 생성해서 작업을 처리하고, 처리 완료 되면 해당 쓰레드 제거하고 ~ 이 작업을 손수 해야 할 것을 ExecutorService가 쉽게 처리해준다.

 

 

2. 어떤 식으로 처리하는지 ?

ExecutorService에 task만 지정해주면 알아서 쓰레드풀로 task를 실행하고 관리함

>> task는 뭘로 관리하는데? Queue로 관리됨, 쓰레드풀에 있는 쓰레드 수보다 task가 많으면, 미실행된 task는 Queue에 저장되고, 실행을 마친 쓰레드로 할당되어 순차적으로 수행됨.

 

 

- ExecutorService가 제공하는 퍼블릭 메소드들은 두 가지로 분류가능

   . 라이프 사이클 관리를 위한 기능들

   . 비동기 작업을 위한 기능들

 

 

"라이프 사이클 관리를 위한 기능들"

  • shutdown
    • 새로운 작업들을 더 이상 받지 않음
    • 호출 전에 제출된 작업들은 그대로 실행이 끝나고 종료됨.
  • isShutdown
    • Executor의 shutdown 여부 반환
  • isTerminated
    • shutdown 실행 후 모든 작업의 종료 여부를 반환
  • awaitTermination
    • shutdown 실행 후, 지정한 시간 동안 모든 작업이 종료될 때까지 대기함
    • 지정한 시간 내에 모든 작업이 종료되었는지 여부를 반환함

 

 

"비동기 작업을 위한 기능들"

비동기 작업의 진행을 추적할 수 있도록 Future를 반환한다.

 

  • submit
    • 실행할 작업들을 추가하고, 작업의 상태와 결과를 포함하는 Future를 반환
    • Future의 get을 호출하면 성공적으로 작업이 완료된 후 결과를 얻을 수 있음
  • invokeAll
    • 모든 결과가 나올 때까지 대기하는 블로킹 방식 요청
    • 동시에 주어진 작업들을 모두 실행하고, 전부 끝나면 각각의 상태와 결과를 갖는 List<Future> 반환
  • invokeAny
    • 가장 빨리 실행된 결과가 나올 때까지 대기하는 블로킹 방식 요청
    • 동시에 주어진 작업들을 모두 실행하고, 가장 빨리 완료된 하나의 결과를 Future로 반환받음.

 

@Test
void invokeAll() throws InterruptedException, ExecutionException {
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    Instant start = Instant.now();

    Callable<String> hello = () -> {
        Thread.sleep(1000L);
        final String result = "Hello";
        System.out.println("result = " + result);
        return result;
    };

    Callable<String> mang = () -> {
        Thread.sleep(4000L);
        final String result = "Java";
        System.out.println("result = " + result);
        return result;
    };

    Callable<String> kyu = () -> {
        Thread.sleep(2000L);
        final String result = "kyu";
        System.out.println("result = " + result);
        return result;
    };

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

    System.out.println("time = " + Duration.between(start, Instant.now()).getSeconds());
    executorService.shutdown();
}



// 코드 출처 : https://mangkyu.tistory.com/259

 

 

 


 

 

[ Executors ]

- 앞에서 본 ExecutorService 는 쓰레드 풀을 위한 인터페이스이다. 직접 쓰레드를 다루는게 번거로워서 이를 도와주는 팩토리 클래스인 Executors가 등장했다.

 

  • newFixedThreadPool
    • 고정된 쓰레드 개수를 갖는 쓰레드 풀 생성
    • ExecutorService 인터페이스를 구현한 ThreadPoolExecutor 객체가 생성됨.
  • newCachedThreadPool
    • 필요할 때 필요한 만큼의 쓰레드 풀 생성
    • 이미 생성된 쓰레드가 있으면 재활용 가능
  • newScheculedThreadPool
    • 일정시간 뒤 또는 주기적으로 실행되야 하는 작업을 위한 쓰레드 풀 생성
    • ScheduledExecutorService 인터페이스를 구현한 ScheduledThreadPoolExecutor 객체가 생성됨
  • newSingleThreadExecutor, newSingleThreadScheduledExecutor
    • 1개의 쓰레드를 갖는 쓰레드 풀 생성
    • 각각 newFixedThreadPool와 newScheculedThreadPool에 1개의 쓰레드만을 생성하도록 한 것

 

 

Executors를 통해 쓰레드의 개수 및 종류를 정할 수 있으며, 이를 통해 쓰레드 생성과 실행 및 관리가 매우 용이해진다.

하지만 쓰레드 풀을 생성 시에는 주의해야 한다.

만약 newFixedThreadPool을 사용해 2개의 쓰레드를 갖는 쓰레드 풀을 생성했는데, 3개의 작업을 동시에 실행시킨다면 1개의 작업은 실행되지 못한다.

그러다가 쓰레드가 작업을 끝내고 반환되어 가용가능한 쓰레드가 생기면 남은 작업이 실행된다.

 

 

 

 

 

 

 

 

 

 

참고 :https://mangkyu.tistory.com/259   ,  https://simyeju.tistory.com/119

728x90
반응형