단순히 비동기처리 기능만 구현하려면 비동기로 작업을 수행하려는 메서드 위에 @Async만 붙여주면 된다. 하지만 이 방법은 스레드를 생성만 하고 따로 관리는 하지 않기 때문에 위험한 방법이고, 프록시 객체 관련해서 클래스 내부의 @Async는 적용되는 않는 상황이 발생할 수 있으므로 주의해야 한다.
@EnableAsync 애노테이션은 스프링 컨텍스트에 비동기 처리를 위한 관련 빈들을 등록한다.
@SpringBootApplication이 사용된 클래스에 @EnableAsync를 사용하게 되면, @SpringBootApplication에 포함된 @Configuration 애노테이션과 충돌하게 되어, 중복된 설정이 발생할 수 있습니다.
그러므로 Async 설정 클래스를 만들어서 @EnableAsync
를 붙여준다.
@Configuration
@EnableAsync // 비동기 어노테이션을 사용할 수 있게 함
public class AsyncConfig {
@Bean(name = "defaultTaskExecutor", destroyMethod = "shutdown")
public ThreadPoolTaskExecutor defaultTaskExecutor(){
ThreadPoolTaskExecutor defaultTaskExecutor = new ThreadPoolTaskExecutor();
defaultTaskExecutor.setCorePoolSize(10);
defaultTaskExecutor.setMaxPoolSize(20);
defaultTaskExecutor.setKeepAliveSeconds(3);
return defaultTaskExecutor;
}
@Bean(name = "messagingTaskExecutor", destroyMethod = "shutdown")
public ThreadPoolTaskExecutor messagingTaskExecutor(){
ThreadPoolTaskExecutor messagingTaskExecutor = new ThreadPoolTaskExecutor();
messagingTaskExecutor.setCorePoolSize(10);
messagingTaskExecutor.setMaxPoolSize(20);
messagingTaskExecutor.setKeepAliveSeconds(3);
return messagingTaskExecutor;
}
}
ThreadPoolTaskExecutor
는 스레드를 관리한다. 위의 코드는 스레드풀을 2개 만들었고, 아래가 기본적인 과정이다.
1 .corePoolSize 만큼 스레드를 생성한다.
2. workQueue 에 task를 담는다
3. workQueue 가 다 차면 maxiumPoolSize 만큼 새로운 스레드 생성한다.
4. keepAliveSeconds에 설정된 시간만큼 스레드를 사용하지 않으면 회수한다.
private final EmailService emailService;
/**
* 2번과 2번은 비동기 처리가 되지 않는다
* 비동기 처리를 하기위해서는 프록시 객체가 필요한데 2번은 등록된 빈이 아니고 3번은 프록시객체가 아니다
*/
public void asyncCall_1(){
System.out.println("[asyncCall_1] : " + Thread.currentThread().getName());
emailService.sendEmail();
emailService.sendMailWithCustomThreadPool();
}
public void asyncCall_2(){ // 객체를 생성해서 인스턴스 내의 메서드를 사용하는 경우
System.out.println("[asyncCall_2] : " + Thread.currentThread().getName()); // 이 메서드를 처리하는 스레드의 이름을 가지고 온다
EmailService emailService1 = new EmailService();
emailService1.sendEmail();
emailService1.sendMailWithCustomThreadPool();
// 하나의 스레드가 처리
}
public void asyncCall_3(){
// @Async가 선언된 클래스 내의 메서드를 사용하는 경우
System.out.println("[asyncCall_3] : " + Thread.currentThread().getName()); // 이 메서드를 처리하는 스레드의 이름을 가지고 온다
}
@Async
public void sendMail(){
System.out.println("[sendEmail] : "+ Thread.currentThread().getName());
}
1번 메서드는 빈으로 등록된 비동기 메서드를 사용하는 경우로 문제없이 비동기가 작동한다. 즉, sendEmail메서드
와 sendMailWithCustomThreadPool메서드
는 다른 스레드로 처리가 된다.
-참고
동기? 비동기? 쓰레드? 멀티 쓰레드?
https://steady-coding.tistory.com/611