Future接口
Future接口(FutureTask实现类)定义了操作异步任务执行一些方法,如获取异步任务执行的结果、取消任务的执行、判断任务是否取消、判断任务执行是否完成等。它提供了一种并行异步计算的功能。比如主线程让子线程去执行任务,子线程比较耗时,启动子线程开始执行任务后,主线程就去做别的事情了,过一会才去获取子任务的执行结果。
Runable接口
Runnable
接口只包含一个抽象方法 void run()
,该方法被线程调用以执行任务。我们可以实现Runnable
接口,并在 run()
方法中编写具体的任务逻辑。一旦线程对象启动后,它将会调用实现了 Runnable
接口的对象的 run()
方法来执行任务。通过实现Runnable
接口,我们可以将任务逻辑与线程对象分离开来。这样可以使代码更清晰、结构化,并更容易维护和扩展。
Callable接口
与Runnable
不同,Callable
接口的任务可以返回一个结果。这样可以通过获取任务的返回值来处理和利用执行结果。
RunnableFuture接口
RunnableFuture
接口它继承了Runnable
和Future
接口,表示一个可运行的、可以返回结果的任务。如下图:
FutureTask类
FutureTask
类实现了RunnableFuture
接口的具体类。
现在FutureTask具备了Runnable接口的能力,因此可以作为可运行的任务被执行。同时实现了Future接口可,以获得任务的执行结果。如何将任务的结果返回呢?而使用Callable
接口可以解决这个问题,Callable
接口定义了一个带有返回值的任务。FutureTask的构造参方法需要传入一个Callable对象。这样一来,使用FutureTask
类可以方便地创建并管理异步计算任务,并获取其执行结果。
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
FutureTask使用案例
通过get()方法阻塞获取结果
public class _FutureTask案例 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(() -> {
Thread.sleep(3000);
return "Task completed successfully";
});
//启动线程执行任务
new Thread(futureTask).start();
//通过get()方法阻塞获取结果(当然可以通过设置超时时长)
String result = futureTask.get();
System.out.println(result);
}
}
通过isDone()轮询获取结果
public class _FutureTask案例 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(() -> {
Thread.sleep(3000);
return "Task completed successfully";
});
//启动线程执行任务
new Thread(futureTask).start();
// 通过isDone()方法轮询获取结果
while (true) {
if (futureTask.isDone()) {
String result = futureTask.get();
System.out.println(result);
return;
} else {
//200毫秒轮询一次
TimeUnit.MILLISECONDS.sleep(500);
System.out.println("休息一下····");
}
}
}
}
FutureTask缺点
- get()方法获取结果容易导致阻塞,一般不这么写(如果硬要这么写的话,一般放在程序最后)
- 通过isDone()轮询方法获取需要不停的轮询会耗费CPU资源,也不见得能及时获取到结果