Java - 异步 - 线程池

标签 java multithreading asynchronous

我正在尝试了解 java 中异步的好处。

场景 1: 我有一个 Spring Boot Web 应用程序部署到 tomcat,tomcat 最小和最大线程都设置为 200。

@Service
public class MyService{

    public String execute(){
        try {
            //simulate blocking 
            Thread.sleep(3000);
        } catch (InterruptedException e) {}
        return "OK";      
    }
}

@RestController
public class MyController {

    @Autowired
    private MyService service;

    @RequestMapping("/test")
    public String test(){
        return service.execute();
    }
}

场景 2:我有一个 Spring Boot Web 应用程序部署到 tomcat,tomcat 最小和最大线程均设置为 100

@Service
public class MyService{

    public String execute(){
        try {
            //simulate blocking 
            Thread.sleep(3000);
        } catch (InterruptedException e) {}
        return "OK";      
    }
}

@RestController
public class MyController {

    @Autowired
    private MyService service;

    private ExecutorService executorService = Executors.newFixedThreadPool(100);

    @RequestMapping("/test")
    public DeferredResult<String> test(){
        DeferredResult<String> deferredResult = new DeferredResult<>();
        CompletableFuture.supplyAsync(service::execute, executorService).
            whenCompleteAsync((result, throwable) -> deferredResult.setResult(result));    
        return deferredResult;      
    }
}

在每个场景中,线程总数均为 200。

但我不认为场景 2 会表现得更好:

在场景 1 中,如果同时传入 400 个请求,则前 200 个请求将由 200 个 http 线程提供服务,接下来的 200 个请求将必须等待 3 秒(加上一点),直到其中一个线程再次可用。

因此吞吐量为每 6 秒 400 个请求 = 每秒 66.6 个请求。

平均响应时间为 (200 * 3 + 200 * 6)/(400) = 4.5 秒

在场景 2 中, 如果同时有 400 个请求进来。前 100 个请求将立即由 100 个 http 线程提供服务,每个线程将调用服务,不等待结果,然后立即恢复,并可用于服务接下来的 100 个请求。 但现在对于第二个 100 个请求,当每个 http 线程调用该服务时,该服务当前正在等待 3 秒(减去一点)来完成处理前 100 个线程。所以接下来的 100 个会排队(在 executorservice 的线程池中)。 因此,我们几乎很快就处理了所有 400 个请求,但是 100 个正在服务中处理(等待 3 秒),而 300 个在执行程序服务线程池中排队。 3 秒后,前 100 个处理完成,接下来的 100 个出列并处理,依此类推。

因此吞吐量为 12 秒内 400 个请求 = 每秒 33.3 个请求

平均响应时间为 (100 * 3 + 100 * 6 + 100 * 9 + 100 * 12)/(400) = 7.5 秒

现在,有人可能会说,“我可以通过增加执行程序服务线程池中的线程数来改进场景 2”,对此我可以回答,“好吧,那么我可以将场景 1 中 tomcat 池中的线程数增加相同的数量”

最佳答案

要在这种情况下看到异步的优势,您需要使您的服务也异步。它不会执行占用线程的 sleep ,而是在安排三秒后完成时运行某些内容后立即返回。在这种情况下,所有请求将在三秒多一点的时间内完成;您的吞吐量为每秒 133 个请求,平均响应时间为三秒。如果您将线程计数调低,您将获得基本相同的响应时间。

异步的要点是,空闲等待 I/O 的线程可以立即空闲下来执行其他操作,因此您不必使用尽可能多的线程(这是一种昂贵的资源)来满足您的工作负载。

关于Java - 异步 - 线程池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42912521/

相关文章:

java - 传递参数以及多部分/表单数据上传表单(Java Http Post Upload)

java - Hibernate 错误地映射 BigDecimal

c# - 锁定对象字典以减少 C# 中的延迟?

c++ - Winsock 多客户端多线程,电脑辛苦了

ios - 异步加载 UIView

c# - 转换/包装一个使用回调的 "classic"异步方法

java - 如何从 JUnit 线程中断信号量?

java - 从 Realm 中获取通用类型的 Realm 对象

c - Linux线程和进程

javascript - JQueryUI Autocomplete 如何处理异步结果?