code.7z
一、概述
通常任务执行过程都是同步进行的,来看一个简单同步执行代码
// ① 获取数据,耗时较长,阻塞
Object data = getData();
// ② 其他事务1
doOther1();
// ③ 其他事务2
doOther2();
// ④ 处理 ① 获取到的结果
doProcessData();
在上面伪代码中,①,②,③ ,④ 按照顺序进行执行,并且每一个步骤都需要等待上一个步骤完成,才能执行。
现在假定每一个步骤的执行耗时如下:
- ① 耗时 10s
- ② 耗时 5s
- ③ 耗时 4s
- ④ 耗时 3s
则执行耗时时间线如下:
上述伪代码中 ,① 和 ④ 存在关联性,但是和 ②,③ 与 ①,④ 之间互不关联,不过 ②,③ 需要等待 ① 执行完成才能执行。
现在有一个需求:在代码执行过程中 ① 不进行同步阻塞,在调用 ① 之后直接进行返回,然后执行 ②,③ ,最后执行 ④ 时,由于与 ① 存在关联,等待 ① 执行完成,然后执行 ④。
通过上述方案,减少 ① 的等待时间,提高程序运行效率。
通过 Future 设计模式能够实现上述需求
Future 实现的原理图,如下:
简单剖析步骤:
step1、方法调用 ① 获取数据,直接创建一个 Thread 后台进行执行,然后返回一个 Future 用以查询执行状态(《观察者模式监控线程生命周期》)
step2、在执行 ②,③ 操作时,后台同样有一个线程在执行 ①
step3、当执行 ④ ,需要一来到 ① 获取的结果时,通过 Future 获取结果。
- 如果 Thread 后台执行完成了,则 Future 能够直接拿到执行结果
- 如果 Thread 后台执行未完成,则进行阻塞,等待 Thread 执行完成
在引入了 Future 设计后,执行时间线如下:
如上图,整体的运行提高了 9 s。
二、代码实现案例
回顾一下上述的伪代码
// ① 获取数据,耗时较长,阻塞
Object data = getData();
// ② 其他事务1
doOther1();
// ③ 其他事务2
doOther2();
// ④ 处理 ① 获取到的结果
doProcessData();
2.1、常规实现
实现上述案例,代码结构图如下:
执行逻辑
用户通过 FutureService#submit
提交执行任务,得到一个 Future
凭证,当需要得到执行结果时通过 Future#get
获取执行结果。
通过实现,执行逻辑优化为
// ① 获取数据,耗时较长,异步执行
Future future = FutureService.submit(getData());
// ② 其他事务1
doOther1();
// ③ 其他事务2
doOther2();
// ④ 通过 Future 获取 ① 的执行结果,然后执行数据处理
Object data = future.get();
doProcessData();
2.2、带有回调的 Future 设计
上述代码中,虽然 ① 通过异步的方式提高了执行效率,但是仍然需要等待 ① 执行结束,然后进行
④ 的处理。
优化:提供回调方法,当 ① 异步执行完成后,主动调用 ④ ,而无需代码主动去调用。
优化后的伪代码如下:
// ① 获取数据,耗时较长,异步执行,同时提供回到方法 doProcessData()/也就是 ④
Future future = FutureService.submit(getData(),doProcessData());
// ② 其他事务1
doOther1();
// ③ 其他事务2
doOther2();