当线程池已满时,如果我的线程休眠大于保持活动秒数,会发生什么情况?

What happens if my thread sleep is greater than the keep alive seconds when the thread pool is full?

我有一个 spring 引导应用程序,用户在其中访问端点,我必须承认我立即收到了他们的请求。我需要在不同的线程上进行一些计算,并在计算结束后在不同的端点上向它们发送响应。为了在不同线程上执行任务,我的线程池配置如下所示:

@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;  
    }  
}

当我进行计算时,我需要点击其中一个端点,returns 给我一个令牌 ID 并进行一些计算。计算通常需要 3 到 4 分钟。所以我所做的是我提到了 Thread.sleep(30000),在 30 秒完成后,我再次使用它提供的令牌 ID 再次点击相同的 api,希望它能给我一个结果。

while(result == false) {
    Thread.sleep(30000)
    result = callendpoint(tokenid)
}

假设我的线程池用完了,它达到了 15 个线程的最大大小,并且向池提供了更多任务,我的一些线程将处于 30 秒睡眠状态,这些线程是否会被终止和分配一个新任务,因为我处于睡眠(空闲)状态?我是否应该添加 set keep alive 以防止这种情况发生?

threadPoolTaskExecutor.setKeepAliveSeconds(120); 

这样做正确吗?

Suppose my thread is exhausted it reached maximum size of 15 and some more tasks are provided to the thread, some of my thread will be 30 seconds sleep state

这可能会发生。这种队列是使用 LinkedBlockingQueue 实现的,行为如下(来源 Spring Framework 5.3.X reference documentation: 7.4.2. The executor Element):

  1. 如果达到 queueCapacity,则执行程序会创建一个 新线程,超出 corePoolSize,直到 maxPoolSize
  2. 如果线程数 maxPoolSize 也达到了 queueCapacity,则任务被 拒绝

默认容量是unlimited(实际上是Integer.MAX_VALUE),这意味着只会分配corePoolSize个线程。如果你想间隙队列容量,记得设置 maxPoolSizecorePoolSize 高一点。为确保不会拒绝任何任务,您必须在 coremax 线程数之间找到合适的平衡点。当然,所有这些数字在很大程度上取决于预期的吞吐量。使用“无限”队列容量,您无需担心这一点,但是,performance-tuning 也有点受限。


threadPoolTaskExecutor.setKeepAliveSeconds(120);

Is this the right thing to do?

我不这么认为。谈到上面的代码片段,请注意 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 方法
  • 不能从定义的class中调用
  • return类型必须是void(更适合工作)或Future