首页 > 解决方案 > Spring Boot:我们可以为每个请求设置单独的线程池吗?

问题描述

我已经使用 Spring Boot @Async 为我的应用程序中的方法实现了异步执行。我有一个带有 20 个线程的自定义线程池。在 for 循环中调用 async 方法 30 次。

每个单独的请求都是异步执行的,但是当我从浏览器同时向我的 API 发出两个不同的请求时,第一个请求正在执行,然后是第二个请求。不是两个请求并行执行相同的方法。

我想当第一个请求到达应用程序时,它开始执行异步方法,并且由于它正在执行 30 次并且我的池有 20 个线程,所有线程都忙于执行第一个请求。因此,即使第二个请求也因为线程池繁忙而执行,另一个请求正在等待线程池中的线程空闲。

我们可以为每个单独的请求设置单独的线程池吗?或者我们可以使每个请求的执行独立于其他请求处理的任何方式。

这是我的代码示例。

@SpringBootApplication
@EnableAsync
public class AppBootStrap
{
  public static void main(String[] args)
  {
    SpringApplication.run(AppBootStrap.class, args);
  }

  @Bean
  public AsyncTaskService asyncTaskService() {
    return new AsyncTaskService();
  }

  @Bean(name="customExecutor")
  public Executor taskExecutor() {
    ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
    poolExecutor.setCorePoolSize(10);
    poolExecutor.setMaxPoolSize(20);
    poolExecutor.setThreadNamePrefix("customPoolExecutor");
    poolExecutor.initialize();
    return poolExecutor;
  }
}

**Controller Class:**

@RestController
public class TaskController
{
  @Autowired
  private TaskService taskService;

 @RequestMapping("/performAction")
 public void performAction() {
    taskService.performAction();
 }
}

**Service class**

@Service
public class TaskService
{
  @Autowired
  private AsyncTaskService asyncTaskService;

  public void performAction()
  {
    for(int i = 0; i < 30; i++) {
        asyncTaskService.greetings(i);
    }
  }
}

**Async Method Class**

public class AsyncTaskService
{
  @Async
  public void greetings(Integer i)
  {
    try
    {
        Thread.sleep(500 * (i + 10));
    }
    catch (InterruptedException e)
    {
        e.printStackTrace();
    }
    System.out.println("Welcome to Async Service: " + i);
  }
}

标签: javamultithreadingspring-bootthreadpoolexecutor

解决方案


    @Bean(name = "apiTaskExecutor")
    public ThreadPoolTaskExecutor apiTaskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(20);
    executor.setMaxPoolSize(100);
    executor.setQueueCapacity(50);
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    executor.initialize();
    return executor;
}

@Bean(name = "lruTaskExecutor")
    public ThreadPoolTaskExecutor lruTaskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(100);
    executor.setMaxPoolSize(200);
    executor.setQueueCapacity(500);
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    executor.initialize();
    return executor;
}

这样做的方法是使用不同的限定符名称创建两个不同的线程池。(如上图)

    @Autowired
    @Qualifier("apiTaskExecutor")
    private ThreadPoolTaskExecutor apiTaskExecutor;

然后使用您给定的限定符自动装配所需的池。您也可以使用@Async注解代替自动装配。我更喜欢这种方式。

如果我没记错的话,这种为不同任务使用不同线程池的方式被称为隔板模式。


推荐阅读