본문 바로가기

Back-End/SpringBoot

[SpringBoot] 병렬, 비동기 처리 wiki

* 이해한 만큼만 정리

parallelStream

  • 비동기 처리는 아니고 병렬 처리
  • 쓰레드 수가 임의로 지정되기 때문에 위험
  • 짧게 끝날 수 있는 병렬 처리에 사용해야겠다고 결심
List <Store> storeList = storeListPage.getContent();

storeList.parallelStream()
    .forEach(
        store - > {
            ...
        });

 

ExecutorService

  • 스레드 풀을 생성하고 관리할 수 있음
  • execute() : 반환 값 없을 때
  • submit() : 반환 값 있을 때
  • 스레드 반환 shutdown() 필수
private void scrapExecuteAsync(List < String > keywords) {
     ExecutorService executorService = Executors.newFixedThreadPool(3);

     keywords.forEach(keyword ->
         executorService.submit(
             () -> scrapService.scrap(keyword)));

     executorService.shutdown();
 }
private void scrapExecuteAsync(List <Request> requestList) {
    ExecutorService executor = Executors.newFixedThreadPool(6);
    List < CompletableFuture <Void>> futures = new ArrayList <> ();

    requestList.forEach(request - > {
        CompletableFuture <Void> future = CompletableFuture.runAsync(() - >
           scrapService.scrap(request) , executor);
        futures.add(future);
    });

    CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
    executor.shutdown();
}

 

CompletableFuture

  • 비동기 작업을 위한 다양한 기능 제공
  • runAsync : 반환 값 없을 때
  • supplyAsync : 반환 값 있을 때
  • thenApply : 반환 값을 받아서 처리 후 다른 값을 반환
  • thenAccept: 반한 값을 받아서 처리 후 값을 반환하지 않음
  • thenRun : 반환 값을 받지 않고 다른 작업 처리
private void scrapExecuteAsync(String keyword) {
    ExecutorService executor = Executors.newFixedThreadPool(1);

    CompletableFuture.supplyAsync(() -> scrapService.scrap(Request.builder()
            .keyword(keyword)
            .build()), executor)
        .thenAccept(response -> saveResponse(response));

    executor.shutdown();
}

 

ExecutorService.submit() vs CompletableFuture.supplyAsync()

둘의 비동기 처리도 가능하고 값을 반환 받는 것도 동일한데 무슨 차이가 있을까

CompletableFuture는 thenApply, thenAccept 메소드를 조합하여 연쇄적인 작업을 할 수 있다.