Main thread가 task를 처리하는 게 아니라 sub thread에게 task를 위임하는 행위
spring에서 비동기 프로그래밍을 위해서 threadPool 정의가 필요
java에서는 threadPool을 생성하여 Async 작업을 처리
순서 : 코어풀 사이즈 만큼 스레드를 생성 → 큐에 테스크를 담고 → 큐가 다 찼을 경우 맥시멈 풀 사이즈 만큼 새로운 스레드를 생성
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());
}
}
실행 결과