多线程——Future和Callable

在并发编程中,我们经常用到非阻塞的模型,在之前的多线程的三种实现中,不管是继承Thread类还是实现Runnable接口,都无法保证获取到之前的执行结果。但是通过实现Callable接口,并用Future可以来接收多线程执行结果。

英文含义:
callable 可收回的
future 未来
Executor [?ɡ?zekj?t?r] (一哥在kei特) 执行器
Future表示一个可能还没有完成的异步任务的结果,针对这个结果可以添加callable以便在任务执行成功或失败后作出相应的操作。
线程池提交实现Callable接口的线程会返回一个Future对象。
Java并发编程:Callable、Future和FutureTask
1. Callable和Runnable Runnable是一个接口,它里面只声明了一个run方法。
public interface Runnable { public abstract void run(); }

但是run()方法返回值是void类型,所以在执行任务之后无法返回任何结果。
而Callable位于java.util.concurrent(并发包)包下,他也是一个接口,它里面也只声明了一个方法。
public interface Callable { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ V call() throws Exception; }

并且,这个接口是一个泛型接口,call方法返回类型就是传递进来的类型。
2. Future 一般情况下,Callable配合ExecutorSevice来使用,获取到的返回值就是Future类型
Future submit(Callable task); Future submit(Runnable task, T result); Future submit(Runnable task);

Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,get方法会阻塞直到任务的完成。
public interface Future { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }

  • cancel(mayInterruptIfRunning) 取消正在运行时的线程。需要注意的时,本质上是依赖线程进程中的(sleep,wait,join-->本质上均是NEW状态)的interrupt方法抛出异常来进行线程的中断的。详情请参考 FutureTask的cancel方法真的能终止正在运行的线程吗?
  • isCanselled方法表示任务是否被取消成功,如果任务正常完成前被取消成功,则返回true。
  • isDone 方法表示任务是否已经完成,若任务完成,则返回true。
  • get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回。
  • get(long timeout,TimeUnit unit)用来获取执行结果,如果在指定时间内,还未获取到结果,就直接返回null。
Future提供了三种功能:
  1. 判断任务是否完成;
  2. 能够中断任务;
  3. 能够获取到任务执行结果;
3. FutureTask 多线程——Future和Callable
文章图片
Future继承关系类图.png Future同时实现了runnable接口和Future接口。故它既可以作为Runnable接口被线程执行,又可以作为Future得到Callable的返回值。
1. FutureTask的参数:Callable
@Test public void testTask() throws InterruptedException, ExecutionException {ExecutorService executorService = Executors.newSingleThreadExecutor(); //线程池提交任务 FutureTask futureTask = new FutureTask(() -> { System.out.println("子线程在进行计算"); Thread.sleep(3000); int sum = 0; for (int i = 0; i < 100; i++) sum += i; return sum; }); //因为FutureTask实现了Runnable接口,故可以使用Thread启用 Thread thread=new Thread(futureTask); thread.start(); //也可以使用线程池的方式使用 executorService.submit(futureTask); executorService.shutdown(); //关闭线程池Thread.sleep(1000); System.out.println("task运行结果"+futureTask.get()); System.out.println("所有任务执行完毕"); } }

【多线程——Future和Callable】如果为了取消性而使用Future但又不提供可用的结果,则可以声明Future形式参数,并返回null作为底层任务结果~

    推荐阅读