future设计模式思想是在进行一个耗时操作时可以让另外一个线程来执行这个耗时任务,主线程继续执行其他任务。
具体实现用下面一个买奶茶例子来讲解:
顾客去奶茶店点一杯奶茶,奶茶需要时间进行制作,此刻顾客可以有以下三种选择
- 在店里等待直到奶茶做好(未使用future设计模式)
- 奶茶店打印一张小票给顾客,顾客拿到小票后不用一直在店里等待可以先去做其他事情然后凭小票到店里领取奶茶(方法调用后立即返回future凭证,执行在恰当的时间通过凭证获取结果)
- 顾客给奶茶店留下自己的联系方式当奶茶做好后主动打电话通知顾客(传入回调方法,任务执行完成后主动回调)
/**
* 代表一个未来的凭证
*
* @param <T>
*/
public interface Future<T> {
/**
* 获取执行结果
*
* @return
* @throws InterruptedException
*/
T get() throws InterruptedException;
}
/**
* 异步future实现
*
* @param <T>
*/
public class AsyncFuture<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;
}
}
/**
* 需要执行的逻辑代码的一个模板
*
* @param <T>
*/
@FunctionalInterface
public interface FutureTask<T> {
/**
* 执行动作
*
* @return
*/
T call();
}
/**
* 类似桥接
*/
public class FutureService {
/**
* 提交任务,并启动一个线程来执行任务
* 然后立即返回一个凭证
*
* @param task 需要执行的任务
* @param <T>
* @return
*/
public <T> Future<T> submit(final FutureTask<T> task) {
AsyncFuture<T> future = new AsyncFuture<>();
new Thread(() -> {
//调用call方法执行任务
T call = task.call();
//任务执行完成后处理凭证信息
future.done(call);
}).start();
return future;
}
/**
* 不需要主动来获取结果,任务执行完成后会主动回调
*
* @param task 需要执行的任务
* @param consumer 回调
* @param <T>
* @return
*/
public <T> void submit(final FutureTask<T> task, final Consumer consumer) {
AsyncFuture<T> future = new AsyncFuture<>();
new Thread(() -> {
//执行任务
T call = task.call();
//任务执行完成后主动回调
consumer.accept(call);
}).start();
}
}
package future;
/**
* future设计模式测试类
*/
public class futureTest {
public static void main(String[] args) throws InterruptedException {
FutureService futureService = new FutureService();
//主动去获取执行结果
Future future1 = futureService.submit(() -> {
try {
// 使用睡眠来模拟此操作很耗时
Thread.sleep(5_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 123;
});
System.out.println("任务提交完成,继续做其他事情");
//主线程睡眠,模拟耗时任务
Thread.sleep(8_000);
System.out.println("其他任务执行完成");
System.out.println("future的执行结果为:" + future1.get());
System.out.println("=================================================");
//执行完成后自动回调
/**
* 此处为了简洁使用了函数式编程
* 第一个参数为一个继承了FutureTask的类
* 第二个参数为一个继承了Consumer的类
*/
futureService.submit(() -> {
try {
// 使用睡眠来模拟此操作很耗时
Thread.sleep(5_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "活干完了,主动回调";
},System.out::println);
System.out.println("任务提交完成,继续做其他事情");
//主线程睡眠,模拟耗时任务
Thread.sleep(8_000);
System.out.println("其他任务执行完成");
}
}
jdk提供的future实现