分析
-
Future模式的核心在于:
去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑。
-
Future模式有点类似于商品订单。在网上购物时,提交订单后,在收货的这段时间里无需一直在家里等候,可以先干别的事情。类推到程序设计中时,当提交请求时,期望得到答复时,如果这个答复可能很慢。传统的是一直持续等待直到这个答复收到之后再去做别的事情,但如果利用Future模式,其调用方式改为异步,而原先等待返回的时间段,在主调用函数中,则可以用于处理其他事务。
总结来说:就是在调用一个很复杂的函数时,不需要等待其完成,而是采用异步的方式执行其他的代码
一个同步的例子
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
- 可以看到代码并没有因为任务的执行而陷入阻塞