비동기 프로그래밍

may_yun·2024년 2월 5일
1

Spring

목록 보기
4/4

Main thread가 task를 처리하는 게 아니라 sub thread에게 task를 위임하는 행위

sub thread 생성 및 관리

spring에서 비동기 프로그래밍을 위해서 threadPool 정의가 필요

java에서는 threadPool을 생성하여 Async 작업을 처리

  • corePoolSize : 해당 스레드풀에 최소한 스레드를 몇개 가지고 있을 것인가
    • 너가 크게 설정할 경우 side effect 고려
  • MaxPoolSize : 최대한 스레드를 몇개 할당할 것인가
  • WorkQueue : 먼저 들어온 요청을 먼저 처리할 수 있도록 큐에 저장
  • KeepAliveTime : 스레드들이 일을하지 않으면 자원을 반납하겠다. Long 타입

순서 : 코어풀 사이즈 만큼 스레드를 생성 → 큐에 테스크를 담고 → 큐가 다 찼을 경우 맥시멈 풀 사이즈 만큼 새로운 스레드를 생성

주의

config

package dev.be.javaasyncpractice.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
public class AppConfig {

    @Bean(name = "defaultTaskExecutor", destroyMethod = "shutdown")
    public ThreadPoolTaskExecutor defaultTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(200);
        executor.setMaxPoolSize(300);

        return executor;
    }

    @Bean(name = "messagingTaskExecutor", destroyMethod = "shutdown")
    public ThreadPoolTaskExecutor messagingTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(200);
        executor.setMaxPoolSize(300);

        return executor;
    }
}
package dev.be.javaasyncpractice.config;

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

@Configuration
@EnableAsync//비동기 동작
public class AsyncConfig {
}

controller

package dev.be.javaasyncpractice.controller;

import dev.be.javaasyncpractice.service.AsyncService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class AsyncController {

    private final AsyncService asyncService;

    @GetMapping("/1")
    public String asyncCall_1() {
        asyncService.asyncCall_1();
        return "success";
    }

    @GetMapping("/2")
    public String asyncCall_2() {
        asyncService.asyncCall_2();
        return "success";
    }

    @GetMapping("/3")
    public String asyncCall_3() {
        asyncService.asyncCall_3();
        return "success";
    }

}

service

package dev.be.javaasyncpractice.service;

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

@Service
@RequiredArgsConstructor
public class AsyncService {

    //비동기 스레드 개발을 할 때는 thread Pool name을 찍어보는 습관을 들일 것
    private final EmailService emailService;

    public void asyncCall_1() {
				//비동기 O
        //bean 주입
        System.out.println("asyncCall_1 :: " + Thread.currentThread().getName());
        emailService.sendMail();
        emailService.sendMailWithCustomThreadPool();
        /*
        bean으로 주입받은 랩핑된 프록시 객체로 사용
        sub thread에게 위임
         */
    }

    public void asyncCall_2() {
        //인스턴스 생성 ( 비동기 X 동기적으로 동작)
				//spring bean 스프링 컨테이너의 도움을 받지 않기 때문에 하나의 스레드로 처리
        System.out.println("asyncCall_2 :: " + Thread.currentThread().getName());
        EmailService emailService = new EmailService();
        emailService.sendMail();
        emailService.sendMailWithCustomThreadPool();
    }

    public void asyncCall_3() {
        //내부 메서드에 Async (비동기 X)
        System.out.println("asyncCall_3 :: " + Thread.currentThread().getName());
        sendMail();
    }

    @Async
    public void sendMail() {
        System.out.println("sendMail :: " + Thread.currentThread().getName());
    }

}
package dev.be.javaasyncpractice.service;

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

@Service
@RequiredArgsConstructor
public class EmailService {
    @Async("defaultTaskExecutor")
    public void sendMail() {
        System.out.println("sendMail: " + Thread.currentThread().getName());
    }

    @Async("messagingTaskExecutor")
    public void sendMailWithCustomThreadPool() {
        System.out.println("messagingTaskExecutor: " + Thread.currentThread().getName());
    }
}

실행 결과

profile
개발 일지

0개의 댓글