Java http请求的线程池

Java http请求的线程池,java,multithreading,performance,http,concurrency,Java,Multithreading,Performance,Http,Concurrency,关于并发的体系结构和性能,我有几个问题 设置: 有一个JavaFXGUI,用户可以在其中启动各种任务,这些任务本身就是线程化任务(new-Thread(new-CustomTask).start();)。这些任务对~700k HTTP请求执行循环,如果在为数据库准备的insert语句中有大约10k个项目,则插入已处理的返回值。它们的进度显示在GUI中(ObservableListitems) 问题: 这些任务需要很长时间,瓶颈似乎是等待HTTP响应时的延迟。 (DB插入是在关闭自动提交的情况下

关于并发的体系结构和性能,我有几个问题

设置: 有一个JavaFXGUI,用户可以在其中启动各种任务,这些任务本身就是线程化任务(
new-Thread(new-CustomTask).start();
)。这些任务对~700k HTTP请求执行循环,如果在为数据库准备的insert语句中有大约10k个项目,则插入已处理的返回值。它们的进度显示在GUI中(
ObservableList
items)

问题: 这些任务需要很长时间,瓶颈似乎是等待HTTP响应时的延迟。 (DB插入是在关闭自动提交的情况下完成的,以10k准备好的插入语句为单位)

目标: 通过将请求放在单独的任务/线程中来提高总体性能


问题1: 在这里使用线程是否合理?如何以其他方式提高性能

问题2: 如果线程是合理的,我如何实现它? 我在考虑建立一个全局线程池或
ExecutorService
,请求任务在其中排队。当响应可用时,它将被写入同步列表。如果列表中有10k+个对象,请执行批插入

问题3: 如何确定好的线程池大小?如何区分线程

Thread.activeCount()
返回7(当前线程组)
ManagementFactory.getThreadMXBean().getThreadCount()
返回13个线程(总线程数?)
Runtime.getRuntime().availableProcessors()
返回8

我读过一些关于多线程的评论,他们都说拥有比核心更多的线程并不一定能提高性能(没有“真正的”并发,时间限制)。我不知道,但是如果我不得不猜测的话,我会说数字13包括一些GUI线程。我似乎不知道如何获得线程池大小的有用数字



我非常感谢任何关于如何改进我的应用程序的提示。当然,您可以使用
ExecutorService

我读过一些关于多线程的评论,他们都说拥有比核心更多的线程并不一定能提高性能(没有“真正的”并发,时间限制)

对于不睡眠或等待/阻塞的进程,如计算素数或处理图像,这是正确的。在您的例子中,HTTP客户机阻塞,直到响应返回,并且直到响应发生,线程才保持空闲。对于HTTP请求,大小为50-100-200的执行器池是可以的

模式可以如下所示:

ExecutorService es = Executors.newFixedThreadPool(50);

// ...
// creating request and response future associated with it
Future<Response> responseFuture = es.submit(new Callable<Response>() {
    @Override
    public Response call() throws Exception {
        // request data by HTTP
        return response;
    }
});
customTask.push(responseFuture);
Q1

首先,不清楚您需要用什么回复客户。您是否必须与数据库对话才能返回响应

如果您不知道这是发布/订阅模式(即它的fire and forget),那么消息队列或任何发布/订阅系统都是理想的,并且比使用普通的
ExecutorService
扩展性好得多。例如,JMS和其他许多例子

您可以通过回复客户端来执行发布/订阅,但这通常需要像WebSockets、Comet这样的非阻塞客户端连接,而且设置起来相当复杂

第二季度和第三季度

如果您的问题是您确实需要回复客户机,那么它遵循请求/回复模式,这是一个更难扩展的问题

JVM上有一些做得很好的库,它们遵循命令和隔板模式,提供可配置和容错的请求/应答,我相信这可以解决您的问题:“如果列表中有10k+对象,请执行批插入。”

对于阻塞操作来说,计算合适的池大小实际上相当复杂。对于非阻塞(即cpu绑定或内存处理),它只是可用的处理器,但这不是您的情况,因为您连接到数据库,并且可能使用阻塞IO servlet容器


为了确定阻塞操作的适当池大小,您将使用Hystrix提供的现成指标和监控。您还应该了解下游依赖关系。例如,如果您的数据库只能处理200个并发连接,则您不希望与数据库对话的线程池大于200。

如果瓶颈正在等待与外部实体(HTTP服务器)之间的IO完成,并且没有太多其他有用的工作要做,则无法加快客户端的速度。也许,你可以调查为什么会有大量的响应延迟?因为它是一个外部实体(不在我的控制之下),我不能影响响应速度。如果他们的服务器有糟糕的一天,我承诺等待。我最初的想法是通过同时发送更多请求来利用“等待时间”。向无法处理现有请求的服务器发送更多请求可能会适得其反;)或者想法是将请求发送到其他地方?服务器确实正确地处理了请求,并没有那么慢,只是我试图改进的应用程序中最慢的部分;)我不介意响应延迟,但是通过发送更多的请求,我可以在服务器回复第一批发送的请求时处理更多的响应。您需要为
结果使用并发数据结构,或者在其上进行同步。您的答案也不是很容错,因为您没有为
响应.get()提供任何超时。我可以继续说使用普通的旧ExecutorService有多糟糕,但我想这是一个选项。@AdamGent我将结果集合移动到对象中,它在单个服务线程中处理,所以现在不需要同步。并添加了超时,谢谢。@AdamGent顺便说一句,发送请求时可以在HTTP客户端上定义超时,以及重试策略。@SashaSalauyou感谢您的解释和示例。您指定50-100-200为游泳池大小。由于这是一个相当广泛的范围,那么所述数字的相关性是什么?这取决于se
// create single pool executor in order to accept responses 
// one by one and at the order they're requested
ExecutorService customTaskService = Executors.newSingleThreadExecutor(); 
List<Response> results = new ArrayList<>();    

// push() method
public void push(final Future<Response> responseFuture) {

     customTaskService.execute(new Runnable() {

         public void run() {
             try {
                 // response.get() will block inside this service thread
                 // though not affecting GUI thread
                 results.add(response.get(TIMEOUT, TimeUnit.SECONDS)); 
             } catch (RuntimeException e) {
                 // processing of a request failed
             }
             if (results.size() > MAX_SIZE) {
                 // make inserts to DB
                 results.clear();
             }
         }
     });
}