我有一个spring-boot应用程序,用户在其中到达一个端点,我必须确认我立即收到了他们的请求。我需要在不同的线程上进行一些计算,并在计算结束后在不同的端点上向它们发送响应。对于在不同的线程上执行任务,我的线程池配置如下所示:
@Configuration
@EnableAsync
public class SpringAsyncMatchingConfig {
@Bean(name = "threadTaskExecutor")
public TaskExecutor getMatchingTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setQueueCapacity(0);
threadPoolTaskExecutor.setMaxPoolSize(15);
return threadPoolTaskExecutor;
}
}
当我进行计算时,我需要到达其中一个端点,该端点会返回一个令牌id并进行一些计算。计算通常需要3到4分钟。因此,我所做的是,我提到了Thread.sleep(30000)
,在30秒后,我再次使用它提供的令牌id访问同一个api,希望它能给我一个结果。
while(result == false) {
Thread.sleep(30000)
result = callendpoint(tokenid)
}
假设我的线程池用完了,它达到了15个线程的最大大小,并且向池中提供了更多的任务,我的一些线程将处于30秒睡眠状态,这些线程会因为我处于睡眠(空闲(状态而被终止并分配新任务吗?我应该添加"保持活动"集以防止这种情况发生吗?
threadPoolTaskExecutor.setKeepAliveSeconds(120);
这样做对吗?
假设我的线程已经耗尽,它达到了最大大小15,并且向线程提供了更多的任务,我的一些线程将处于30秒睡眠状态
这是可能发生的。这样的队列是使用LinkedBlockingQueue
实现的,其行为如下(源Spring Framework 5.3.X参考文档:7.4.2。executor
元素(:
- 如果达到
queueCapacity
,则执行器将创建一个新线程,该线程位于corePoolSize
之外,直至maxPoolSize
- 如果
queueCapacity
也达到maxPoolSize
线程数,则任务被拒绝
默认容量是无限的(实际上是Integer.MAX_VALUE
(,这意味着将只分配corePoolSize
数量的线程。如果要使队列容量间隔,请记住将maxPoolSize
设置为比corePoolSize
高一点。为了确保不会拒绝任何任务,您必须找到core
和max
线程数量的适当平衡。当然,所有这些数字在很大程度上取决于预期吞吐量。用一个";"无限";队列容量,您不需要担心,但是,性能调优也有点有限。
threadPoolTaskExecutor.setKeepAliveSeconds(120);
这样做对吗?
我不这么认为。说到上面的片段,请注意,Thread.sleep(30000)
这么长的时间并不能帮助您进行有效的结果轮询,而可以通过CompletableFuture
进行处理。当5分钟后结果不可用时,使用CompletableFuture::get(long timeout, TimeUnit unit)
停止线程。看看下面你能做什么:
@Component
public class AsyncClient {
@Async
public CompletableFuture<Result> fetchResult(String tokenId) {
Result result = callEndpoint(tokenId); // a long call
return CompletableFuture.completedFuture(results);
}
}
@Service
public class TokenService {
private final AsyncClient asyncClient;
public Result callEndpoint(String tokenId)
throws InterruptedException, ExecutionException, TimeoutException
{
CompletableFuture<Result> completableFuture = asyncClient.fetchResult(tokenId);
return completableFuture.get(5, TimeUnit.SECONDS);
}
}
最后,让我提醒您使用@Async
的三个基本规则:
- 它只能应用于
public
方法 - 它不能从定义的同一类中调用
- 返回类型必须是
void
(更适合作业(或Future