Future设计模式
当执行一个操作时,需要执行很长时间的阻塞。而future设计模式可以使并不阻塞当前的执行,让本线程可以继续向下执行。当需要结果的时候我去拿就好了。
创建Future接口
这是一个一个未来接口,当方法调用时立即返回一个Future,根据future的get方法可以拿到返回的值。
public interface Future<T> {
T get() throws InterruptedException;
}
创建FutureTask接口
这是一个任务接口,这个接口有call方法来执行核心任务
public interface FutureTask<T> {
T call() throws InterruptedException;
}
创建FutureService
用来提交未来的任务FutureTask,在这里当提交任务时就立刻返回一个Future,其他线程可以通过Future的get来同步拿到方法执行的返回值
public class FutureService {
public <T>Future<T> submit(final FutureTask<T> task){
AsynFuture<T> asynFuture = new AsynFuture();
new Thread(()->{
T result = null;
try {
result = task.call();
} catch (InterruptedException e) {
e.printStackTrace();
}
asynFuture.done(result);
}).start();
return asynFuture;
}
}
创建AsynFuture(Future的实现)
提供了get()方法,注意get方法是同步的。当线程执行完了会向AsynFuture的setResult放置数据
public class AsynFuture<T> implements Future<T> {
private volatile boolean done = false;
private T result;
public void done(T result){
synchronized (this){
this.result = result;
done = true;
this.notifyAll();
}
}
@Override
public T get() throws InterruptedException {
synchronized (this){
while(!done){
this.wait();
}
}
return result;
}
}
创建测试类
public class MainApplication {
public static void main(String[] args) throws InterruptedException {
FutureService futureService = new FutureService();
Future<String> future = futureService.submit(() -> {
try {
Thread.sleep(5_000);
} catch (Exception e) {
e.printStackTrace();
}
return "FINISHED";
});
System.out.println("----------------");
System.out.println(" do others work");
Thread.sleep(2_000);
System.out.println("----------------");
System.out.println(future.get());
}
}
操作结果分析
很明显FutureService的submit不会阻塞当前方法的执行,但是当调用Get时此时程序会陷入阻塞,同步等待方法执行完。
存在的问题及解决方案
问题:在以上代码获取result的方式是通过get的方式去询问就算没有准备好数据也要阻塞当前线程。可不可以当准备好自己通知我呢?
解决方式:使用callback回调的方式,在futureService重载submmit方法
public <T> void submit(final FutureTask<T> task, Consumer<T> consumer){
new Thread(()->{
try {
T res = task.call();
consumer.accept(res);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
测试
public class MainApplication2 {
public static void main(String[] args) {
FutureService futureService = new FutureService();
futureService.submit(()->{
Thread.sleep(5_000);
return "测试";
},MainApplication2::callback);
System.out.println("-----------");
System.out.println("同步阻塞检测");
System.out.println("-----------");
}
public static <T> void callback(T res){
System.out.println(res);
}
}