V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
aoscici2000
V2EX  ›  Java

还是 Futrue.get() 堵塞当前线程的问题

  •  
  •   aoscici2000 · 2019-05-29 14:02:12 +08:00 · 1701 次点击
    这是一个创建于 1765 天前的主题,其中的信息可能已经有所发展或是发生改变。
    
    @RestController
    public class ThreadController {
    
    	@Resource(name = "taskExecutor")
    	private ThreadPoolTaskExecutor executor;
    
    	@GetMapping("/check")
    	public Map<String, Object> check() throws Exception{
    
    		Map<String, Object> map = new HashMap<>();
    
    		Future<Integer> pa = executor.submit(new CheckPrice(a));
    		Future<Integer> pb = executor.submit(new CheckPrice(b));
    		Future<Integer> pc = executor.submit(new CheckPrice(c));
    
    		Integer[] priceList = { pa.get(), pb.get(), pc.get() };
    		map.put("最小价格", Collections.min(Arrays.asList(priceList)));
    
    		return map;
    	}
    }
    
    

    假设每个 CheckPrice 需要 2 秒耗时, 有多人同时访问"/check"的时候, 怎样才能让每个人都只是等 2 秒, 而不用排队一个个处理?

    貌似只要是需要等待 Future.get 结果的, controller 都是堵住的, CompletableFuture 也看了一个早上, 好像也会堵 controller, 或者返回空值的...

    8 条回复    2019-05-31 23:00:03 +08:00
    phx13ye
        1
    phx13ye  
       2019-05-29 14:05:05 +08:00
    你咋测的,executor 里的线程够不够啊,如果你 executor 有 6 个线程,同时两人访问,这两个人就是等两秒啊,不是四秒啊
    aoscici2000
        2
    aoscici2000  
    OP
       2019-05-29 14:17:11 +08:00
    @phx13ye 开 8 线测 2 人, 结果有一个得等 4 秒...
    sujin190
        3
    sujin190  
       2019-05-29 15:01:52 +08:00
    纯 cpu 计算但是双核 cpu ?
    firefffffffffly
        4
    firefffffffffly  
       2019-05-29 15:06:27 +08:00
    1. 你这里涉及到两个多线程,一个是 check()请求函数发生的线程池 executorA,一个是你自己定义执行 CheckPrice 的 executorB
    2. 你的问题和 executorB 没有太大关系,它的线程数只影响 Future.get()的耗时,最少 2s, 任何类型的 Future.get()一样会阻塞至少 2s。
    3. 由 2 可知你每次 check()函数被调用最少会阻塞 2s,这时 executorA 如果是单线程模型,两个请求一定会有一个等待 4s。
    4. executorA 线程数取决于 servlet 容器的配置

    解决方案
    1. 修改 servlet 的配置,增加 executorA 线程数,治标不治本,优点是简单
    2. check()修改为异步非阻塞返回模型,参考你之前帖子里 9 楼回复的 CompletableFuture + DeferredResult 方案
    Jrue0011
        5
    Jrue0011  
       2019-05-31 16:28:51 +08:00
    ThreadPoolTaskExecutor 内部其实就是创建了一个 ThreadPoolExecutor 吧,需要指定 queueCapacity,默认是 Integer.MAX_VALUE,你可以指定为 1 或者 0 试试看...不然队列不满的话是不会去创建新线程执行任务的
    Jrue0011
        6
    Jrue0011  
       2019-05-31 16:34:46 +08:00
    @Jrue0011 仔细看了下,ThreadPoolTaskExecutor 默认的 corePoolSize=1,线程池的逻辑好像是这样的,一开始有 corePoolSize 的线程,如果这些线程都被使用则新任务进入队列,如果队列满了则创建新线程直到 maxPoolSize,所以也可能是线程池的 corePoolSize 是默认的 1。。。
    Jrue0011
        7
    Jrue0011  
       2019-05-31 17:37:00 +08:00   ❤️ 1
    刚刚自己写了个测试下,第二个请求响应慢的问题可能是出在浏览器(chrome,其他浏览器没测试)上。。。用 postman 同时发两个请求,响应的时间就基本一样了
    aoscici2000
        8
    aoscici2000  
    OP
       2019-05-31 23:00:03 +08:00
    @Jrue0011 晕死了, chrome 好像真有点大坑, 之前一直觉得刷新两个窗口来试试就行...结果浏览器一直有毛病, 用脚本测一下才正常...
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   952 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 21:12 · PVG 05:12 · LAX 14:12 · JFK 17:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.