分析
-
Future模式的核心在于:
去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑。
-
Future模式有点类似于商品订单。在网上购物时,提交订单后,在收货的这段时间里无需一直在家里等候,可以先干别的事情。类推到程序设计中时,当提交请求时,期望得到答复时,如果这个答复可能很慢。传统的是一直持续等待直到这个答复收到之后再去做别的事情,但如果利用Future模式,其调用方式改为异步,而原先等待返回的时间段,在主调用函数中,则可以用于处理其他事务。
总结来说:<mark>就是在调用一个很复杂的函数时,不需要等待其完成,而是采用异步的方式执行其他的代码</mark>
一个同步的例子
public class SyncInvoker {
public static void main(String[] args) throws InterruptedException {
//get方法的阻塞导致了主函数的阻塞
String result = get();
System.out.println(result);
}
private static String get() throws InterruptedException {
//模拟一个很耗时的操作
Thread.sleep(10_000);
return "FinISH";
}
}
- 执行的get操作会阻塞住主线程的工作
Future模式
先设计一个接口,代表未来的凭据
,相当于***
/** * 获取结果 * Furture 代表未来的凭据,相当于买的火车票 * @param <T> */
public interface Furture<T> {
T get() throws InterruptedException;
}
实现Future接口
有两个方法
- 一个方法交给其他线程在完成任务后,将结果放入到结果集
- 一个方法负责提取结果集的数据,如果此时没用做完,就陷入阻塞
/** * 一个Future的实现类 * 有两个方法 * 一个方法交给其他线程在完成任务后,将结果放入到结果集 * 一个方法负责提取结果集的数据,如果此时没用做完,就陷入阻塞 * @param <T> */
public class AsynFuture<T> implements Future<T> {
private volatile boolean done = false;
private T result;
/** * 当完成工作后,负责写入数据 * @param result */
public void done(T result){
synchronized (this){
this.result = result;
this.done = true;
this.notifyAll();
}
}
/** * 判断是否完成,如果完成,将结果返回 * 如果没有,陷入阻塞 * @return * @throws InterruptedException */
@Override
public T get() throws InterruptedException {
synchronized (this){
while (!done){
this.wait();
}
}
return result;
}
}
设计一个桥梁桥接Future和FutureTask
主要思想是:
- 设计一个线程执行FutureTask的任务,在执行完成后,放到asynFuture的结果集中
- 返回asynFuture的结果集,供主方法自由的调用
/** * 桥接Future和FutureTask */
public class FutureService {
public <T> Future<T> submit(FutureTask<T> task) {
AsynFuture<T> asynFuture = new AsynFuture<>();
//创建一个线程专门负责执行任务
new Thread(()->{
T result = task.call();
asynFuture.done(result);
}).start();
return asynFuture;
}
public <T> void submit(FutureTask<T> task, Consumer<T> consumer) {
AsynFuture<T> asynFuture = new AsynFuture<>();
//创建一个线程专门负责执行任务
new Thread(()->{
T result = task.call();
asynFuture.done(result);
consumer.accept(result);
}).start();
}
}
测试
public class AsynClient {
public static void main(String[] args) throws InterruptedException {
FutureService futrueService = new FutureService();
Future<String> future = futrueService.submit(() -> {
try {
Thread.sleep(5_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "FINISH";
});
System.out.println("我先去忙啦");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我看看你完成没有");
System.out.println(future.get());
// futrueService.submit(()->{
// try {
// Thread.sleep(3_000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// return "FINISH";
// },System.out::println);
// System.out.println("我先去忙啦");
}
}
结果:
我先去忙啦
我看看你完成没有
FINISH
- 可以看到代码并没有因为任务的执行而陷入阻塞