题目案例

已知一个业务查询操作涉及 3 个 RPC 服务调用 : query1, query2, query3, 其中query1 耗时约 1 秒, query2 耗时约 0.5 秒,query3 耗时约 0.6 秒,且query3查询条件依赖 query2 的查询结果.请编写代码,使该业务查询总体耗时最小:

考察点 1:异步
考察点 2:多线程并发控制

解题思路:
主要考察知识点异步和多线程控制。

如果采用串行执行,query1+query2+query3 总耗时为 2.1 秒。

采用多线程异步并行执行,使用线程 A 请求 query1,同时使用线程 B 请求query2后再请求 query3(query3 依赖 query2 结果只能串行执行),这样总耗时是 min(1, 0.5+0.6) = 1.1 秒。

需要熟悉 join, CountDownLatch 等线程协调控制方法,如果考生使用线程池则更佳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
public void queryTest1(){
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(2, 10, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5, true), new ThreadPoolExecutor.CallerRunsPolicy());
long start = System.currentTimeMillis();

Thread thread1 = new Thread(() -> {
query1();
});
Thread thread2 = new Thread(() -> {
query2();
});
Thread thread3 = new Thread(() -> {
query3();
});

thread1.start();
thread2.start();
try {
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
thread3.start();
try {
thread3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

long time = System.currentTimeMillis() - start;
System.out.println("耗时 " + time);
poolExecutor.shutdown();
}


public void queryTest(){
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(2, 10, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5, true), new ThreadPoolExecutor.CallerRunsPolicy());
CountDownLatch downLatch = new CountDownLatch(1);
CountDownLatch mainLatch = new CountDownLatch(3);
long start = System.currentTimeMillis();

poolExecutor.execute(() -> {
query1();
mainLatch.countDown();
});

poolExecutor.execute(() -> {
query2();
downLatch.countDown();
mainLatch.countDown();
});

poolExecutor.execute(() -> {
try {
downLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
query3();
mainLatch.countDown();
});

try {
mainLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
long time = System.currentTimeMillis() - start;
System.out.println("耗时 " + time);
poolExecutor.shutdown();
}

public void query1(){
System.out.println(DateUtil.date().toString("yyyy-MM-dd HH:mm:sss ") + Thread.currentThread().getName() + "query1");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void query2(){
System.out.println(DateUtil.date().toString("yyyy-MM-dd HH:mm:sss ") + Thread.currentThread().getName() + "query2");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void query3(){
System.out.println(DateUtil.date().toString("yyyy-MM-dd HH:mm:sss ") + Thread.currentThread().getName() + "query3");
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}