아래 내용은 아래 토비의 스프링 유투브를 보고 고대로 따라친 테스트 내용이다.
https://www.youtube.com/live/aSTuQiPB4Ns?feature=share
https://m.facebook.com/story.php?story_fbid=pfbid08M9d9CqchaB8tqsUZq3wMSpkZEK6b3BhENq6tTAnsHU9fEo8UGcQBoG6QFrDymVRl&id=1070166746&mibextid=qC1gEa
최근에 이직한 회사에서 익숙했던 javaScript(nodejs)가 아닌 자바를 쓰게되었다.
자바의 reactiveRepository를 사용하게 되었는데. 비동기 작업에 대한 이해도를 높이기 위해 영상을 보다가 궁금증이 들어서 해본 테스트 결과이다.
Caused by: org.springframework.core.task.TaskRejectedException: Executor [java.util.concurrent.ThreadPoolExecutor@6cd15072[Running, pool size = 10, active threads = 10, queued tasks = 5, completed tasks = 0]] did not accept task: org.springframework.aop.interceptor.AsyncExecutionInterceptor$$Lambda$660/0x00000008004dd040@3c0e00a8
System.out.println(Arrays.toString(run.getBeanDefinitionNames()));
// ..., taskExecutorBuilder, applicationTaskExecutor, ...
public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {
private final Object poolSizeMonitor = new Object();
private int corePoolSize = 1;
private int maxPoolSize = Integer.MAX_VALUE;
@ConfigurationProperties("spring.task.execution")
public class TaskExecutionProperties {
private final Pool pool = new Pool();
private final Shutdown shutdown = new Shutdown();
/**
* Prefix to use for the names of newly created threads.
*/
private String threadNamePrefix = "task-";
public Pool getPool() {
return this.pool;
}
public Shutdown getShutdown() {
return this.shutdown;
}
public String getThreadNamePrefix() {
return this.threadNamePrefix;
}
public void setThreadNamePrefix(String threadNamePrefix) {
this.threadNamePrefix = threadNamePrefix;
}
public static class Pool {
/**
* Queue capacity. An unbounded capacity does not increase the pool and therefore
* ignores the "max-size" property.
*/
private int queueCapacity = Integer.MAX_VALUE;
/**
* Core number of threads.
*/
private int coreSize = 8;
/**
* Maximum allowed number of threads. If tasks are filling up the queue, the pool
* can expand up to that size to accommodate the load. Ignored if the queue is
* unbounded.
*/
private int maxSize = Integer.MAX_VALUE;
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
ThreadPoolTaskExecutor threadPoolTaskExecutor = run.getBean(ThreadPoolTaskExecutor.class);
System.out.println("threadPoolTaskExecutor = " + threadPoolTaskExecutor);
System.out.println("threadPoolTaskExecutor.getThreadNamePrefix()= " + threadPoolTaskExecutor.getThreadNamePrefix());
System.out.println("threadPoolTaskExecutor.getPoolSize() = " + threadPoolTaskExecutor.getPoolSize());
System.out.println("threadPoolTaskExecutor.getCorePoolSize() = " + threadPoolTaskExecutor.getCorePoolSize());
System.out.println("threadPoolTaskExecutor.getMaxPoolSize() = " + threadPoolTaskExecutor.getMaxPoolSize());
System.out.println("threadPoolTaskExecutor.getQueueSize() = " + threadPoolTaskExecutor.getQueueSize());
System.out.println("threadPoolTaskExecutor.getQueueCapacity() = " + threadPoolTaskExecutor.getQueueCapacity());
}
// threadPoolTaskExecutor = org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor@659f226a
// threadPoolTaskExecutor.getThreadNamePrefix()= task-
// threadPoolTaskExecutor.getPoolSize() = 3
// threadPoolTaskExecutor.getCorePoolSize() = 8
// threadPoolTaskExecutor.getMaxPoolSize() = 2147483647
// threadPoolTaskExecutor.getQueueSize() = 0
// threadPoolTaskExecutor.getQueueCapacity() = 2147483647
package com.example.demo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFuture;
import java.util.concurrent.ThreadPoolExecutor;
@SpringBootApplication
@EnableAsync
@Slf4j
public class DemoApplication {
@Autowired KeroService keroService;
@Bean
ApplicationRunner run() {
return args -> {
log.info("run() start");
for(int i = 0; i < 15; i++) {
// Thread.sleep(2000);
ListenableFuture<String> f = keroService.kero(i);
f.addCallback(System.out::println, error -> System.out.println(error.getMessage()));
}
log.info("run() exit");
Thread.sleep(500000);
};
}
@Component
public static class KeroService {
// SimpleAsyncTaskExecutor -> 1000개 동시요청이 들어오면 thread 1000개를 만들고 캐시/종료 하지않고 남아있음
@Async
public ListenableFuture<String> kero(int i) throws InterruptedException {
log.info("Async start");
Thread.sleep(2000);
log.info("Async exit");
return new AsyncResult<>("zero" + i);
}
}
//
// @Bean
// ThreadPoolTaskExecutor threadPool() {
// ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
// threadPool.setCorePoolSize(2); // 시작시0개 필요한시점 초기에 2개 생성
// threadPool.setQueueCapacity(5); // 7개 요청이 동시에 들어오면 5개는 큐에쌓인다
// threadPool.setMaxPoolSize(10); // 15개 요청이 들어오면 thread가 max까지(10) 늘어난다
// threadPool.setKeepAliveSeconds(3); // 몇초동안 안쓸때 쓰레드를 종료시킬지
// //max보다 queue가 먼저 적용된다.
// threadPool.setThreadNamePrefix("keroro");
// threadPool.initialize();
// return threadPool;
// }
public static void main(String[] args) {
try (ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args)) {}
}
}