在开发中常常会出现一种情况,一个任务需要执行很长的时间,但是你肯定不希望它会阻塞你的线程,在java中有一个Future的类,它相当于一个凭证,当你需要执行结果的时候给你,这个凭证是立即返回的,当你需要的时候去拿结果就行了。
Future与Future的简单实现
public interface Future<T> {
T get() throws InterruptedException;
}
public class MyFuture<T> implements Future<T> {
private T result;
private volatile boolean isDone = false;
public void done(T result) {
synchronized (this){
this.result = result;
isDone = true;
notifyAll();
}
}
@Override
public T get() throws InterruptedException {
while (!isDone) {
synchronized (this) {
wait();
}
}
return result;
}
public interface Task<T> {
T call();
}
public class FutureService<T> {
public Future<T> submit(Task<T> task){
MyFuture<T> future=new MyFuture<>();
Executors.newSingleThreadExecutor().submit(()->{
T call = task.call();
future.done(call);
});
return future;
}
}
测试执行
public class Test {
public static void main(String[] args) {
FutureService<String> futureService =new FutureService<>();
Future<String> future = futureService.submit(() -> {
try {
//模拟处理很重的任务
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "finish";
});
System.out.println("doSomething");
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("will to get");
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
你会发现,不会阻塞主线程,当你提交这个任务后可以做自己的事情,当你需要的时候再去拿。
但是发现另外一个问题,我自己doSomthing的时间可能只有一秒,但是你处理需要10秒,那么我去get()的时候依旧会被阻塞。这样的情况是我们并不想看到的,那么怎么去解决这个问题?
我们在FutureService中添加一个方法
public Future<T> submit(Task<T> task, Consumer<T> consumer){
MyFuture<T> future=new MyFuture<>();
Executors.newSingleThreadExecutor().submit(()->{
T result = task.call();
future.done(result);
consumer.accept(result);
});
return future;
}
你传给我一个Conusmer,是一个回调函数,你告诉我,当结果执行完毕以后你想要去干什么,我回主动帮你去回调这个处理,那么你就可以完全不需要调用get()去获取结果,并进行处理,你只需要提起告诉我你想怎么去处理这个结果,我帮你处理就可以了,在ConmletableFutre,Netty等中大量用到了这种模式,可以非常高效的处理。