๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์™„๋ฒฝ ๊ฐ€์ด๋“œ: @Async์™€ CompletableFuture ํ™œ์šฉ๋ฒ•

mrmount 2024. 10. 21.

 

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐ ํ•„์ˆ˜์ ์ธ ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. Spring Boot ์—์„œ๋Š” @Async ์™€ CompletableFuture ๋ฅผ ์‚ฌ์šฉํ•ด ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„ ๋ฐฉ๋ฒ• , CompletableFuture ๋กœ ๋น„๋™๊ธฐ ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ , ๊ทธ๋ฆฌ๊ณ  ๋น„๋™๊ธฐ ์ž‘์—…์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ „๋žต ๊นŒ์ง€ ์ƒ์„ธํžˆ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

 


 

 

๋ชฉ์ฐจ

  1. ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ž€ ๋ฌด์—‡์ธ๊ฐ€?
  2. @Async์™€ ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„ํ•˜๊ธฐ
  3. CompletableFuture๋ฅผ ์ด์šฉํ•œ ๋น„๋™๊ธฐ ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ
  4. ๋น„๋™๊ธฐ ์ž‘์—… ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ „๋žต
  5. ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์˜ ํŠธ๋ Œ๋“œ์™€ ์žฅ์ 

 


 

1. ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ž€ ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋‹ค๋ฅธ ์ž‘์—…์„ ๊ณ„์† ์ง„ํ–‰ํ•˜๋Š” ๋ฐฉ์‹ ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋Œ€๊ทœ๋ชจ ํŠธ๋ž˜ํ”ฝ์„ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜, ์™ธ๋ถ€ API ํ˜ธ์ถœ๊ณผ ๊ฐ™์€ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์‘๋‹ต ์†๋„๋ฅผ ํ–ฅ์ƒ ์‹œํ‚ต๋‹ˆ๋‹ค.

๋™๊ธฐ ์ฒ˜๋ฆฌ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ
ํ•˜๋‚˜์˜ ์ž‘์—…์ด ์™„๋ฃŒ๋œ ํ›„ ๋‹ค์Œ ์ž‘์—… ์‹œ์ž‘ ์ž‘์—…์„ ๋ณ‘๋ ฌ๋กœ ์ˆ˜ํ–‰ํ•˜์—ฌ ์ฒ˜๋ฆฌ ์†๋„ ์ฆ๊ฐ€
์˜ˆ: ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ํ›„ ์ด๋ฉ”์ผ ์ „์†ก ์˜ˆ: ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ์™€ ์ด๋ฉ”์ผ ์ „์†ก ๋ณ‘ํ–‰

 

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋Š” ์ฃผ๋กœ I/O ์ž‘์—… ์ด๋‚˜ ๋„คํŠธ์›Œํฌ ํ˜ธ์ถœ ์„ ์ตœ์ ํ™”ํ•  ๋•Œ ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

 


 

2. @Async์™€ ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„ํ•˜๊ธฐ

 

@Async๋ฅผ ์‚ฌ์šฉํ•œ ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„

@Async ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” ํ˜ธ์ถœ ์‹œ ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ ๋ฉ๋‹ˆ๋‹ค.

 

์„ค์ •: ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ํ™œ์„ฑํ™”

@EnableAsync ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด ๋น„๋™๊ธฐ ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

package com.example.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

@Configuration
@EnableAsync
public class AsyncConfig {
}

 

๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ ์˜ˆ์ œ

package com.example.demo.service;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class EmailService {

    @Async
    public void sendEmail(String email) {
        System.out.println("์ด๋ฉ”์ผ ์ „์†ก ์ค‘... " + email);
        try {
            Thread.sleep(5000); // ์ด๋ฉ”์ผ ์ „์†ก ์‹œ๋ฎฌ๋ ˆ์ด์…˜
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("์ด๋ฉ”์ผ ์ „์†ก ์™„๋ฃŒ: " + email);
    }
}

์ฝ”๋“œ ์„ค๋ช…

  1. @Async : ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ์—์„œ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
  2. sendEmail() ๋ฉ”์„œ๋“œ๋Š” ํ˜ธ์ถœ ์ฆ‰์‹œ ๋‹ค๋ฅธ ์ž‘์—…๊ณผ ๋ณ‘ํ–‰ ๋˜์–ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

์‹คํ–‰ ๊ฒฐ๊ณผ

์ด๋ฉ”์ผ ์ „์†ก ์ค‘... example@email.com
(5์ดˆ ํ›„)
์ด๋ฉ”์ผ ์ „์†ก ์™„๋ฃŒ: example@email.com

 


 

3. CompletableFuture๋ฅผ ์ด์šฉํ•œ ๋น„๋™๊ธฐ ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ

CompletableFuture ๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์˜ ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค๋Š” ๋น„๋™๊ธฐ ์ž‘์—… ์™„๋ฃŒ ํ›„ ์ž๋™์œผ๋กœ ํ›„์† ์ž‘์—… ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

CompletableFuture ์‚ฌ์šฉ ์˜ˆ์ œ

 

UserService.java

package com.example.demo.service;

import com.example.demo.entity.User;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;

@Service
public class UserService {

    @Async
    public CompletableFuture<User> getUserById(Long id) {
        System.out.println("์‚ฌ์šฉ์ž ์กฐํšŒ ์‹œ์ž‘: " + id);
        try {
            Thread.sleep(3000); // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์กฐํšŒ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        User user = new User(id, "ํ™๊ธธ๋™");
        System.out.println("์‚ฌ์šฉ์ž ์กฐํšŒ ์™„๋ฃŒ: " + user.getName());
        return CompletableFuture.completedFuture(user);
    }
}

 

UserController.java

package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.CompletableFuture;

@RestController
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/users/{id}")
    public CompletableFuture<User> getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }
}

์ž…์ถœ๋ ฅ ์˜ˆ์ œ

์š”์ฒญ :
GET /users/1

์‘๋‹ต :

{
    "id": 1,
    "name": "ํ™๊ธธ๋™"
}

 


 

4. ๋น„๋™๊ธฐ ์ž‘์—… ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ „๋žต

๋น„๋™๊ธฐ ์ž‘์—…์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ์ด๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์ฒ˜๋ฆฌ ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. CompletableFuture ๋Š” handle() ๋ฉ”์„œ๋“œ ๋ฅผ ์ œ๊ณตํ•˜์—ฌ ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ ๋Œ€์ฒด ๋กœ์ง์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋น„๋™๊ธฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์˜ˆ์ œ

public CompletableFuture<User> getUserById(Long id) {
    return CompletableFuture.supplyAsync(() -> {
        if (id == 0) {
            throw new IllegalArgumentException("ID๋Š” 0์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
        }
        return new User(id, "ํ™๊ธธ๋™");
    }).handle((user, ex) -> {
        if (ex != null) {
            System.out.println("์˜ˆ์™ธ ๋ฐœ์ƒ: " + ex.getMessage());
            return new User(0L, "์•Œ ์ˆ˜ ์—†์Œ");
        }
        return user;
    });
}

์ฝ”๋“œ ์„ค๋ช…

  1. supplyAsync() : ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  2. handle() : ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๋Œ€์ฒด ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

 


 

5. ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์˜ ํŠธ๋ Œ๋“œ์™€ ์žฅ์ 

  • ๋Œ€๊ทœ๋ชจ ํŠธ๋ž˜ํ”ฝ ์ฒ˜๋ฆฌ : ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋Š” ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜ ์—์„œ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋น„๋™๊ธฐ API ์‚ฌ์šฉ ์ฆ๊ฐ€ : ๋งŽ์€ ์™ธ๋ถ€ API๊ฐ€ ๋น„๋™๊ธฐ ํ˜ธ์ถœ ์„ ์ง€์›ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ณ ์„ฑ๋Šฅ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ : ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋Š” I/O ๋Œ€๊ธฐ ์‹œ๊ฐ„์„ ์ตœ์†Œํ™” ํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ฑ๋Šฅ์„ ๋†’์ž…๋‹ˆ๋‹ค.
  • ๋น„๋™๊ธฐ ๋ฉ”์‹œ์ง• ์‹œ์Šคํ…œ : Kafka์™€ ๊ฐ™์€ ๋ฉ”์‹œ์ง€ ํ ์‹œ์Šคํ…œ ๊ณผ ๊ฒฐํ•ฉํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

 


 

๊ด€๋ จ ๋งํฌ


Spring ๊ณต์‹ ๋ฌธ์„œ๐Ÿ‘†

CompletableFuture ๊ฐ€์ด๋“œ๐Ÿ‘†

Java ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ๐Ÿ‘†

Spring Boot ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์˜ˆ์ œ๐Ÿ‘†

Java ExecutorService์™€ ์Šค๋ ˆ๋“œ ํ’€๐Ÿ‘†

Spring WebFlux๋กœ ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ๐Ÿ‘†




FAQ

 

1. @Async ๋ฉ”์„œ๋“œ๋Š” ์–ธ์ œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‚˜์š”?

  • ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…(์˜ˆ: ์ด๋ฉ”์ผ ์ „์†ก, ์™ธ๋ถ€ API ํ˜ธ์ถœ)์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค.

2. CompletableFuture์™€ Future์˜ ์ฐจ์ด์ ์€ ๋ฌด์—‡์ธ๊ฐ€์š”?

  • CompletableFuture ๋Š” ํ›„์† ์ž‘์—… ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋น„๋™๊ธฐ ์ž‘์—…์˜ ์™„๋ฃŒ ์‹œ์ ์— ์ฝœ๋ฐฑ์„ ๋“ฑ๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ์—์„œ ๋ฐ˜ํ™˜ ํƒ€์ž…์€ ๊ผญ CompletableFuture์—ฌ์•ผ ํ•˜๋‚˜์š”?

  • ๋น„๋™๊ธฐ ์ž‘์—…์˜ ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด CompletableFuture ๊ฐ€ ๊ถŒ์žฅ๋˜์ง€๋งŒ, void ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4. ๋น„๋™๊ธฐ ์ž‘์—… ์ค‘ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ๋Š” ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋‚˜์š”?

  • CompletableFuture ์˜ handle() ๋˜๋Š” exceptionally() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

5. ์Šค๋ ˆ๋“œ ํ’€์„ ์–ด๋–ป๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‚˜์š”?

  • TaskExecutor ๋ฅผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜์—ฌ ์Šค๋ ˆ๋“œ ํ’€์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 


 

๋งˆ๋ฌด๋ฆฌ

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” Spring Boot์˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•์„ ๋‹ค๋ค˜์Šต๋‹ˆ๋‹ค. @Async ์™€ CompletableFuture ๋ฅผ ์‚ฌ์šฉํ•ด ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ ํ•˜๊ณ , ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ „๋žต ์„ ํ†ตํ•ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์˜ค๋ฅ˜๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ฑ๋Šฅ๊ณผ ์‘๋‹ต ์†๋„ ๋ฅผ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ์ค‘์š”ํ•œ ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ I/O ์ž‘์—…๊ณผ ์™ธ๋ถ€ API ํ˜ธ์ถœ ์—์„œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ๋Œ€๊ทœ๋ชจ ํŠธ๋ž˜ํ”ฝ๋„ ํšจ๊ณผ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CompletableFuture ๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์˜ ์™„๋ฃŒ ์‹œ์ ์— ํ›„์† ์ž‘์—…์„ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์–ด, ๋ณต์žกํ•œ ๋น„๋™๊ธฐ ๋กœ์ง๋„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ฒ˜๋Ÿผ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์™€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฅผ ์ž˜ ๊ฒฐํ•ฉํ•˜๋ฉด, ์•ˆ์ •์ ์ด๊ณ  ์„ฑ๋Šฅ ์ข‹์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ“๊ธ€