前段时间面试,问了一个简单的问题,
当一个服务需要调用多个外部服务时,调用链比较长,当是同步调用时,将会是多个服务响应时间的综合。而我们使用异步的方式,将会取决于最大响应时间的服务。
比如现在有4个服务,学生服务 1秒,教师服务2秒,班级服务3秒,宿舍服务4秒。我们采用同步调用的话,将花费10秒多。
假设 学生服务和班级服务相互依赖。所以组合起来异步调用花费3秒。教师和宿舍服务组合花费4秒。那么将花费7秒左右。
下面使用简单的代码来模拟下场景。
//任务类
public class Task {
public List<Integer> studentService(){
try {
List<Integer> list = new ArrayList<>();
list.add(1);
Thread.sleep(1000);
return list;
} catch (InterruptedException e) {
e.printStackTrace();
return new ArrayList<>();
}
}
public List<Integer> teacherService(){
try {
List<Integer> list = new ArrayList<>();
list.add(1);
Thread.sleep(2000);
return list;
} catch (InterruptedException e) {
e.printStackTrace();
return new ArrayList<>();
}
}
public List<Integer> classService(){
try {
List<Integer> list = new ArrayList<>();
list.add(1);
Thread.sleep(3000);
return list;
} catch (InterruptedException e) {
e.printStackTrace();
return new ArrayList<>();
}
}
public List<Integer> dormitoryService(){
try {
List<Integer> list = new ArrayList<>();
list.add(1);
Thread.sleep(4000);
return list;
} catch (InterruptedException e) {
e.printStackTrace();
return new ArrayList<>();
}
}
}
//线程池工具类
public enum PoolThreadUtil {
Instance;
private ThreadPoolExecutor threadPoolExecutor;
PoolThreadUtil() {
threadPoolExecutor = new ThreadPoolExecutor(4, 4,
2, TimeUnit.SECONDS, new ArrayBlockingQueue(10));
}
private List<Future<Object>> invokeCommands(List<Callable<Object>> callables) {
try {
return this.threadPoolExecutor.invokeAll(callables);
} catch (InterruptedException e) {
e.printStackTrace();
return new ArrayList<>();
}
}
public List<Object> execute(List<Callable<Object>> callables) {
List<Object> resultList = new ArrayList<>();
List<Future<Object>> futureList = this.invokeCommands(callables);
try {
for (Future future : futureList) {
resultList.add(future.get());
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return resultList;
}
public void shutDown(){
this.threadPoolExecutor.shutdown();
}
}
//客户端调用
public static void main(String[] args) {
Test.async();
Test.sync();
PoolThreadUtil.Instance.shutDown();
}
public static void sync() {
Task task = new Task();
List<Object> list = new ArrayList<>();
Long start = System.currentTimeMillis();
list.addAll(task.studentService());
list.addAll(task.classService());
list.addAll(task.teacherService());
list.addAll(task.dormitoryService());
Long end = System.currentTimeMillis();
System.out.println("sync消耗时间——》" + String.valueOf(end - start) + "ms");
}
public static void async() {
Task task = new Task();
List<Object> list = new ArrayList<>();
Long start = System.currentTimeMillis();
List<Callable<Object>> callables = new ArrayList<>();
callables.add(() -> {
return task.studentService();
});
callables.add(() -> {
return task.classService();
});
list.addAll(PoolThreadUtil.Instance.execute(callables));
callables.clear();
callables.add(() -> {
return task.teacherService();
});
callables.add(() -> {
return task.dormitoryService();
});
list.addAll(PoolThreadUtil.Instance.execute(callables));
Long end = System.currentTimeMillis();
System.out.println("async消耗时间——》" + String.valueOf(end - start) + "ms");
}
异步和同步输出对比
async消耗时间——》7124
sync消耗时间——》10002
总结:从结果可以看出来,多线程的方式确实能提高响应速度,但由于线程的数量不是无限的,所以在设计线城市参数时要考虑业务请求以及队列的大小,线程数太少的话,会造成队列请求数过多,反而会导致响应速度更慢。所以线程池的参数要仔细斟酌。