오답노트
[Spring] 비동기 처리 (Async) 본문
Async
비동기 처리는 thread를 통해 다른 작업을 처리하게 만들고 기존 로직은 그대로 실행시키게 하는 것이다.
@SpringBootApplication
@EnableAsync
public class AsyncApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class, args);
}
}
메인 클래스에서 EnableAsync Annotation을 사용하요 비동기를 사용하는 것을 명시한다.
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Slf4j
@Service
public class AsycService {
@Async
public String hello(){
for(int i = 0 ; i < 10 ; i++){
try{
Thread.sleep(2000);
log.info("thead sleep");
}catch (InterruptedException e){
e.printStackTrace();
}
}
return "hello";
}
}
위 처럼 클래스를 정의하고 Service Annotation으로 Spring에 등록한다. 그리고 메소드 중 비동기로 작업할 메소드에 Async Annotation을 사용한다.
CompletableFuture
비동기의 특성 상 비동기에서 반환되는 값을 받는 타이밍과 로직의 진행 타이밍은 다를 수 밖에 없다.
하지만 비동기에서 반환되는 값을 로직에서 활용해야하는 경우가 있는데 이때 사용하는 것이 CompletableFuture다.
@Service
public class AsycService {
@Async()
public CompletableFuture run(){
return new AsyncResult(hello()).completable();
}
@Async
public String hello(){
for(int i = 0 ; i < 10 ; i++){
try{
Thread.sleep(2000);
log.info("thead sleep");
}catch (InterruptedException e){
e.printStackTrace();
}
}
return "hello";
}
}
hello 를 반환하는 비동기 함수 run을 만들었다.
import com.example.async.service.AsycService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.CompletableFuture;
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/api")
public class ApiController {
private final AsycService asycService;
@GetMapping("/hello")
public CompletableFuture hello(){
log.info("CompletableFuture init");
return asycService.run();
}
}
API 에서 마찬가지로 CompletableFuture를 반환하는 함수로 되어있다.
Thread 할당
thread 할당을 정의하지 않으면 Spring이 알아서 해주긴 하지만 사용자가 설정하여 얼마나 어떻게 thread를 할당할지 정의할 수 있다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
public class AppConfig {
@Bean("async-thread")
public Executor asyncThread(){
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setMaxPoolSize(100);
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setQueueCapacity(10);
threadPoolTaskExecutor.setThreadNamePrefix("Async-");
return threadPoolTaskExecutor;
}
}
CorePoolSize는 현재 운용중인 Thread가 부족할 때 추가될 Thread의 개수이다. 하지만 바로 추가되는 것이 아니라 작업을 Queue에 먼저 넣어 놓는다. 만약 작업이 밀려 할당한 Queue에 작업이 꽉 차 있다면, 그때 Thread의 개수를 추가한다. Thread의 최대 개수는 100개 이다.
예를 들면 Thread 10개가 작업을 하고 있는데 추가로 5개가 들어왔으면 Thread는 추가되지 않고 5개는 대기 상태이다.
이때, 추가로 10개가 들어와서 총 15개의 작업이 대기해야하는 상황이면 Thread를 20개로 늘리게된다.
'Java > Spring' 카테고리의 다른 글
[Spring] Server to Server 예제 (네이버 API) (0) | 2023.07.14 |
---|---|
[Spring] Server to Server (0) | 2023.07.14 |
[Spring] Interceptor (0) | 2023.07.14 |
[Spring] Filter (0) | 2023.07.14 |
[Spring] Exception과 Validation (0) | 2023.07.14 |