@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, 或者返回空值的...
1
phx13ye 2019-05-29 14:05:05 +08:00
你咋测的,executor 里的线程够不够啊,如果你 executor 有 6 个线程,同时两人访问,这两个人就是等两秒啊,不是四秒啊
|
2
aoscici2000 OP @phx13ye 开 8 线测 2 人, 结果有一个得等 4 秒...
|
3
sujin190 2019-05-29 15:01:52 +08:00
纯 cpu 计算但是双核 cpu ?
|
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 方案 |
5
Jrue0011 2019-05-31 16:28:51 +08:00
ThreadPoolTaskExecutor 内部其实就是创建了一个 ThreadPoolExecutor 吧,需要指定 queueCapacity,默认是 Integer.MAX_VALUE,你可以指定为 1 或者 0 试试看...不然队列不满的话是不会去创建新线程执行任务的
|
6
Jrue0011 2019-05-31 16:34:46 +08:00
@Jrue0011 仔细看了下,ThreadPoolTaskExecutor 默认的 corePoolSize=1,线程池的逻辑好像是这样的,一开始有 corePoolSize 的线程,如果这些线程都被使用则新任务进入队列,如果队列满了则创建新线程直到 maxPoolSize,所以也可能是线程池的 corePoolSize 是默认的 1。。。
|
7
Jrue0011 2019-05-31 17:37:00 +08:00 1
刚刚自己写了个测试下,第二个请求响应慢的问题可能是出在浏览器(chrome,其他浏览器没测试)上。。。用 postman 同时发两个请求,响应的时间就基本一样了
|
8
aoscici2000 OP @Jrue0011 晕死了, chrome 好像真有点大坑, 之前一直觉得刷新两个窗口来试试就行...结果浏览器一直有毛病, 用脚本测一下才正常...
|