【问题标题】:How to configure a ThreadPool for parallel webservice requests?如何为并行 Web 服务请求配置 ThreadPool?
【发布时间】:2017-07-11 14:06:02
【问题描述】:

我想将 web 服务调用并行发送到 web 服务。最多应有 20 个并行请求等待 Web 服务响应。任何其他请求都应等待它们完成。

如果单个用户向我发送请求,这通常会导致向目标服务器发送 5 个并行请求。 所以我一次最多可以为 20/5 = 4 个用户提供服务。其他人将不得不等待,这很好。或者在非常高的负载下被拒绝。

问题:我应该使用哪个线程池,我应该如何配置它?

private ExecutorService asyncExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(20);
    executor.setMaxPoolSize(20);
    executor.setQueueCapacity(100);
    executor.initialize();

    //return executor.getThreadPoolExecutor(); //I could as well use this. Which is better??
    return Executors.newFixedThreadPool(20, executor);
}

我阅读以上内容如下:主池可以向网络服务器发送 20 个并行请求(从而以并行方式立即为 4 个用户提供服务)。如果所有 20 个线程都忙并且第 5 个用户进来,则请求排队。

问题:

  • 配置正确吗?

  • 为什么我必须在Executors.newFixedThreadPool() 中额外设置nthreads=20?设置poolSize有什么区别?

  • 设置corePoolSize=20 是否存在性能开销?我的意思是,那么游泳池将永远不会减少。但我可能无法将它设置得更低(例如设置为 5),因为只有在队列耗尽时才会创建新线程。对吧?

【问题讨论】:

  • 如果您更仔细地查看ThreadPoolTaskExecutor,您会发现它是ThreadFactoryjava.util.concurrent.ThreadPoolExecutor 类的包装器。调用Executors.newFixedThreadPool 接受ThreadFactory 的实例,并创建另一个包装给定线程工厂的ThreadPoolExecutor。如果您只使用其中一个而不是像这样包装它,则不需要告诉您的配置数据两次。

标签: java spring multithreading web-services parallel-processing


【解决方案1】:

我认为

executor.setMaxPoolSize(20) 

可用于通过构造函数覆盖最初设置的线程数,在这种情况下似乎是多余的。同样适用于setCorePoolSize。只是为了动态控制。 根据池子的大小,一般可以考虑Little's Law

【讨论】:

  • 那么我应该 1) 删除Executors.newFixed...() 语句并使用executor.getThreadPoolExecutor() 构造ExecutorService?或者我应该删除池配置并依赖Executors.newFixed...()
  • @membersound,你绝对不需要两者。应该选择哪一个取决于你是想使用 Spring 的 API 提交还是使用 JDK API 提交。
  • @membersound 选择其中之一,我看不出有什么区别。一般来说,我建议使用Executors.newCachedThreadPool() 来完成这样一个相对较小的任务。
  • 但是如果使用Executors.接口,我该如何限制queueSize呢?
  • 如果你想获得更多的动态控制,你可以通过 ExecutorService 启动,否则通过 Executors。
【解决方案2】:

当调用Executors.newFixedThreadPool(20, executor); 时,您将之前设置的执行器作为ThreadFactory 传递,因为 ThreadPoolTask​​Executor 实现了 ThreadFactory 接口。

结果是一个 ExecutorService,它开始时有 20 个线程就绪,最大线程数 20 和一个无限的 LinkedBlockingQueue 等待处理的任务(你可以在这里看到它https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool(int,%20java.util.concurrent.ThreadFactory))。

至于您的第一个和第二个问题 - 如果您想使用 jdk 类 ThreadPoolExecutor,您可以省略 Executors.newFixedThreadPool() 调用,只返回 ThreadPoolTask​​Executor 或调用 getThreadPoolExecutor()。

至于您的第三个问题 - 启动时会受到惩罚,因为 jvm 必须创建和运行 20 个线程,但我想这可以忽略不计。让您将 corePoolSize 设置为低于 maximumPoolSize 的一件事是 unsed 线程将被 jvm 杀死,这可以减少应用程序的内存占用。

关于 ExecutorService 中何时创建新线程 - 当队列中有任务且未达到 maximumPoolSize 时,将创建 ExecutorService 中的线程。如果达到 executor 中的 maximumPoolSize 并且队列已满 - executor 将为每个提交给它的新任务抛出 RejectedExecutionException ,直到再次有空间容纳新任务。您可以通过实现自己的 RejectedExecutionHandler 来更改此行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-31
    • 1970-01-01
    • 1970-01-01
    • 2012-05-06
    • 2016-01-19
    • 2012-05-13
    • 1970-01-01
    相关资源
    最近更新 更多