@RestController
public class TestController {
@Resource(name = "taskExecutor")
private ThreadPoolTaskExecutor executor;
@GetMapping("/test")
public Map<String, Object> test() throws Exception{
Map<String, Object> map = new HashMap<>();
DemoTask task = new DemoTask();
Future<String> result = executor.submit(task);
map.put("result", result.get());
return map;
}
}
class DemoTask implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(5000);
return "这是要的结果";
}
}
如果两个人几乎同时访问 /test 的时候, 怎么样可以让这两个请求同时处理, 而不需要先等第一个处理完? 假设是需要等待返回结果的.
1
Narcissu5 2019-05-28 19:15:54 +08:00
|
2
pursuer 2019-05-28 19:16:20 +08:00
不想 Future.get()阻塞就在 task 最后加个回调吧
|
3
cyhulk 2019-05-28 19:21:03 +08:00
你可以考虑 spring 的异步相应,直接返回 callable,servelet 3.1 规范支持
|
4
zrc 2019-05-28 19:31:58 +08:00
1. 两个人同时访问 /test 不应该就是两个线程吗( springmvc 处理),除非你的逻辑里面要限制只能一定数量的线程同时访问(信号量)
2. 如果只是为了子线程不影响主线程的执行,并且子线程的结果不需要给客户端返回,那主线程不需要进行 get 操作,如果需要进行返回那等主线程执行到必须要子线程结果的时候,那不是必须要阻塞到子线程的数据吗,否则是没有意义的吧 3. 如果是多个子线程,主线程要等多个都返回,那么可以使用 countdownlatch |
5
micean 2019-05-28 19:34:52 +08:00
class DemoTask implements Runnable{
final HttpServletResponse response; // 省略构造函数 @Override public void run() { String 结果 = ...; response.getWriter().write(结果) } } |
6
HuHui 2019-05-28 19:38:48 +08:00 via Android
你这个需求 Spring Cloud 中的请求合并了解下
|
7
godoway 2019-05-28 21:57:20 +08:00 via Android
看看 CompletableFuture 是不是你想要的
|
8
godoway 2019-05-28 22:07:55 +08:00 via Android
CompletableFuture + DeferredResult
创建一个 DeferredResult,然后在 CompletableFuture 的回调里面 setResult,最后返回 DeferredResult |
9
dengtongcai 2019-05-28 22:39:15 +08:00 via iPhone
CompletableFuture
|
10
beidounanxizi 2019-05-28 23:35:09 +08:00
可以用闭锁 还是栅栏 实现 ?随口一说 2 个都用来控制多线程何时处理的
|
11
aoscici2000 OP @godoway 好像还是不行, 都是早早就返回了空结果.
|
12
nekoneko 2019-05-29 15:49:05 +08:00
看一下,CountDownLatch 或者 CyclicBarrier 吧
|
13
aoscici2000 OP @godoway 这个能说得详细一点不, 这两货看了一天, 单独分开看好像挺多例子都能看得懂一点, 但结合起来就蒙了...尤其结合到例子里的实际需求的时候...
|
14
godoway 2019-05-29 23:20:18 +08:00
@aoscici2000 把 tomcat 的 max-threads 设置为 1,看看日志是不是你想要的那种
``` @GetMapping("defer") fun testDeferred(): DeferredResult<String> { log.info("handle request") val defer = DeferredResult<String>() CompletableFuture.runAsync { Thread.sleep(1000) log.info("async task") defer.setResult("Hello defer") } log.info("defer result") return defer } ``` |
15
aoscici2000 OP @godoway 依然还是回到了那个老问题, 只要我需要拿到最终结果, handler 还是得排队来.
```java @GetMapping("/task") public DeferredResult<String> ast() { DeferredResult<String> defer = new DeferredResult<>(); CompletableFuture.runAsync(new Runnable() { @Override public void run() { Thread.sleep(5000); defer.setResult("结果"); }); return defer; } ``` 好像有点理解不来,,, |
16
godoway 2019-05-30 07:45:12 +08:00 via Android
@aoscici2000 max-threads=1 意味着只有一个线程处理请求,那么同时来 2 个请求的时候,如果使用你之前用的 future 就会阻塞了这唯一一条线程,结果就是 2 个请求合计使用了 10 秒。但使用 CompletableFuture + DeferredResult 时,2 个请求进来了,第一个请求直接返回了 defer 随意该线程已经完成了第一个请求了,接下来就会直接处理第二个请求。而 CompletableFuture 则是在另外一个线程池执行,当他完成时就返回给用户,于是这时的结果是两个请求合计使用 5 秒多一点时间(取决于你 CompletableFuture 的线程池大小,默认是 CPU-1,如果=1 时,也是需要 10 秒了)
|
17
aoscici2000 OP @godoway 运行结果看起来似乎是每个线程不同, 但等结果返回时还是得一个个来
```java @Resource(name = "taskExecutor") private ThreadPoolTaskExecutor executor; @GetMapping("/async-task") public DeferredResult<String> ast() { System.out.println("handler 调用, 当前线程: %s, 当前时间: %s"); DeferredResult<String> defer = new DeferredResult<>(); CompletableFuture.runAsync(new Runnable() { @Override public void run() { Thread.sleep(5000); defer.setResult("这是结果, 当前线程: %s, 当前时间: %s"); System.out.println("这是结果, 当前线程: %s, 当前时间: %s"); }, executor); return defer; } ``` 1 秒内两次请求 /async-task handler 调用, 当前线程: 35, 当前时间: 41:07:277 handler 调用, 当前线程: 42, 当前时间: 41:12:460 这是结果, 当前线程: 50, 当前时间: 41:12:304 这是结果, 当前线程: 51, 当前时间: 41:17:470 |
18
godoway 2019-05-30 11:48:17 +08:00 via Android
@aoscici2000 看起来你的 35 和 42 就相差了 5 秒,确定你的测试用例正确么。
|
19
aoscici2000 OP @godoway 我就简单装着两个人同时访问, 打开两个 localhost/async-task 页面 1 秒内各自刷新了一下, 我想要达到的效果是第二个应该 41:13 就处理了, 41:18 就出结果了
|
20
godoway 2019-05-30 14:56:07 +08:00 1
@aoscici2000
![](//i.imgur.com/L6S5laj.png) 这是 tomcat 只开一个线程,另外一个 worker 线程是 10 个的情况, 由日志可以看出,同时提交 5 个请求,异步的操作是 5 秒后才返回 response。 并不存在你描述的问题,所以你确认你的测试是正确的吗? |
21
aoscici2000 OP @godoway 图打不开, 跳转到其他页面了...
tomcat 这设置了的话, 除了 handler 那的线程 id 就是相同的, 但执行起来结果也是一样 server: tomcat: max-threads: 1 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(8); executor.setMaxPoolSize(16); |
22
aoscici2000 OP @godoway 晕死了, 好像是浏览器的大坑...一直以为就在 chrome 里打开两个标签刷一下就好了, 结果被人提醒用脚本测一下就完全 OK 了, 谢谢了哈, 打扰了那么就哈哈
|