首页 > 解决方案 > 如何在 Spring Boot 应用程序中正确使用 ThreadPoolExecutor

问题描述

我有一个Spring Boot Application.

我的应用程序使用restTemplate.

我需要向一百个不同的应用程序(在不同的服务器上)发送请求。我用:

publi class Service {
    private RestClient restClient;
    private List<String> urls;
    private ThreadPoolExecutor executor;

    public Service(RestClient restClient, List<String> urls, ThreadPoolExecutor executor){
       this.restClient = restClient;
       this.urls = urls;
       this.executor = executor;
    }

    public void sendPost(Entity entity){
         for (String url: urls){
             executor.execute(() -> restClient.create(url, entity);
         }
    }

}

我正在尝试使用ThreadPoolExecutor(fixedSizeThreadPool),但我有一些问题。

1 .我读到这threadPoolExecutor是线程安全的。这是否意味着我可以execute()从不同的线程同时调用并且它会正常工作?
2 . 如果没有空闲线程threadPoolExecutor它会减慢应用程序的速度,我应该选择合理的池大小,对吗?
3 . 例如,我需要在以下位置编写执行的 url ArrayList

public void sendPost(Entity entity){
         List<String> executedUrls = new ArrayList<>();  
         for (String url: urls){
             executor.execute(() -> restClient.create(url, entity, executedUrls);
         }
}

RestClient发送请求,如果执行成功,会被添加到ArrayList.

如果我ArrayList在来自threadPool.
它会按我的预期工作还是我会丢失更新之类的东西?

标签: javaspringmultithreadingconcurrency

解决方案


您可以做的是使用ExecutorService.
例如,创建一个新ExecutorService的(缓存的ThreadPoolExecutor可能更好)

private final ExecutorService executorService = Executors.newCachedThreadPool();

创建自定义Runnable实现

static class RestRunnable implements Runnable {
    private final String url;
    private final RestTemplate restTemplate;
    private final Collection<? super String> executedUrls;

    RestRunnable(
            final String url,
            final RestTemplate restTemplate,
            final Collection<? super String> executedUrls) {
        this.url = url;
        this.restTemplate = restTemplate;
        this.executedUrls = executedUrls;
    }

    @Override
    public void run() {
        final ResponseEntity<?> response = restTemplate.exchange(...);

        if (response.getStatusCode() == HttpStatus.OK) {
            executedUrls.add(url);
        }
    }
}

并为每个URL人提交一个新任务到ExecutorService

final Collection<String> urls = new ArrayList<>();
final Collection<String> executedUrls = new CopyOnWriteArrayList<>();

...

for (final String url : urls) {
    // The RestTemplate instance is retrieved via Spring Bean, or created manually 
    executorService.submit(new RestRunnable(url, restTemplate, executedUrls));
}

RestRunnable如果成功调用,则将其URL插入线程executedUrls安全中。CopyOnWriteArrayList


请记住,不再需要时ExecutorService 必须关闭。


推荐阅读