java - 如何在 Spring Boot 应用程序中正确使用 ThreadPoolExecutor

标签 java spring multithreading concurrency

我有一个 Spring Boot 应用程序

我的应用程序使用 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。例如,我需要在ArrayList中写入执行的url:

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

RestClient发送请求,如果执行成功,就会添加到ArrayList中。

如果我在 threadPool 的任何线程中出现异常,我希望 ArrayList 将包含成功执行的 url 列表。
它会按我的预期工作吗?或者我可能会遇到丢失更新之类的情况?

最佳答案

您可以使用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必须在不再需要时关闭。

关于java - 如何在 Spring Boot 应用程序中正确使用 ThreadPoolExecutor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55269656/

相关文章:

java - 如何在AWS中构建各种微服务组件

spring - 如何用 cucumber 激活 Spring 启动配置文件

linux - Linux 中的线程与进程

java - JFrame 在 Thread.sleep(int) 期间处于非 Activity 状态

java - 按 OK 按钮后 JFace 对话框保持打开状态

java - 如何对 YouTube 视频使用字符串插值

spring - 如何初始化自定义 ItemReader?

Python:我应该子类化 threading.Thread 吗?

java - Java Scanner sc.nextLine(); 问题

java - 计算两个时隙共有的时间