1、基本介绍
Runnable 是一个接口,在它里面只声明了一个 run()方法,由于 run()方法返回值为 void 类型,所以在执行完任务之后无法返回任何结果。
Callable 位于 java.util.concurrent 包下,它也是一个接口,在它里面也只声明 了一个方法,只不过这个方法叫做 call(),这是一个泛型接口,call()函数返回的类型就是传递进来的 V 类型。
Future 就是对于具体的 Runnable 或者 Callable 任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过 get 方法获取执行结果,该方法会阻塞直到任务返回结果。在Future类中一共有5个方法,如下图所示:
cancel(boolean mayInterruptIfRunning) 方法:尝试取消任务,如果任务已经完成、已经被取消或由于某些其他原因而无法取消,则此尝试将失败。 如果成功,并且在调用cancel()时此任务尚未开始,则该任务永远不会运行。 如果任务已经开始,则{@code mayInterruptIfRunning}参数确定是否应中断执行该任务的线程以尝试停止该任务。cancel(false) 不会中断已经运行的任务。
get() 方法:获取线程返回结果,阻塞着获取结果
get(long timeout, TimeUnit unit) 方法:获取线程结果时设置等待时长
isCancelled() 方法:如果此任务在正常完成之前被取消,则返回true,否则返回false
isDone() 方法:如果此任务完成(无论怎么结束的,如异常结束,取消,正常结束),则返回true
由于Future 只是一个接口,无法直接用来创建对象使用,因此就有了下面的FutureTask
三者关系图如下
如上图:FutureTask 类实现了RunnableFuture 接口,RunnableFuture 继承了Runnable接口和Future 接口。所以它既可以作为Runnable被线程执行,又可以作为Future 得到Callable 的返回值
比如我们通过一个线程运行Callable,但是Thread 不支持构造方法中传递Callable的实例,所以我们需要通过FutureTask 把一个Callable 包装成Runnable交给Thread去运行,然后再通过这个FutureTask 拿到Callable 运行后的线程返回值。
要new 一个FutureTask的实例,有两种方法,如下图所示。
2 代码示例
- 类说明:Future的基本使用
package cn.lspj.ch2.future; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * 类说明:Future的使用 */ public class UseFuture { /** * 实现Callable接口,允许有返回值 */ private static class UseCallable implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("Callable 子线程开始计算。。。。。。"); int num = 0; for(int i=0;i<5000;i++){ num += i; } System.out.println("Callable 线程计算结果为 num =" + num); return num; } } public static void main(String[] args) throws ExecutionException, InterruptedException { UseCallable useCallable = new UseCallable(); // 包装callable为FutureTask FutureTask futureTask = new FutureTask(useCallable); new Thread(futureTask).start(); System.out.println("获取子线程Callable计算返回结果:" + futureTask.get()); } }
执行结果
- 类说明:Future的使用,演示在计算过程中中断任务
package cn.lspj.ch2.future; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * 类说明:Future的使用,演示在计算过程中中断任务 */ public class UseFuture { /** * 实现Callable接口,允许有返回值 */ private static class UseCallable implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("Callable 子线程开始计算。。。。。。"); int num = 0; for(int i=0;i<5000;i++){ //判断线程中断标记为状态 if(Thread.currentThread().isInterrupted()){ System.out.println("Callable 子线程计算任务被中断了。。。。。。。。。。"); return null; } Thread.sleep(1); num += i; System.out.println("num=" + num); } System.out.println("Callable 线程计算结果为 num =" + num); return num; } } public static void main(String[] args) throws ExecutionException, InterruptedException { UseCallable useCallable = new UseCallable(); // 包装 FutureTask futureTask = new FutureTask(useCallable); new Thread(futureTask).start(); Thread.sleep(35); Random r = new Random(10); if(r.nextInt() > 5){ System.out.println("获取子线程Callable计算返回结果:" + futureTask.get()); } else { System.out.println("cancle.............."); futureTask.cancel(true); } } }
futureTask.cancel() 其实是改变了线程的中断位标记状态,线程的中断还是要自己实现的
执行结果
————————————————
版权声明:本文为CSDN博主「﹏半生如梦愿梦如真て」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lspj201007186/java/article/details/106247283