29.JAVA异步编程:异步计算助手FutureTask

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_25991865/article/details/88044715

采用 Runnable 实例来表示异步任务,其优点是任务既可以交给一个专门的工作者线程执行(以相应的 Runnable 实例为参数创建并启动一个工作者线程),也可以交给一个线程池或者 Executor 的其他实现类来执行;其缺点是我们无法直接获取任务的执行结果。使用 Callable 实例来表示异步任务,其优点是我们可以通过 ThreadPooIExecutor. submit(Callable) 的返回值获取任务的处理结果;其缺点是Callable 实例表示的异步任务只能交给线程池执行,而无法直接交给一个专门的工作者线程或者 Executor 实现类执行 。 因此,使用 Callable 实例来表示异步任务会使任务执行方式的灵活性大为受限。
java.util.concurrent.FutureTask 类则融合了 Runnable 接口和 Callable 接口的优点:FutureTask既是 Runnable 接口的实现类也是 Future 接口的实现。FutureTask 的一个构造器可以将Callable 实例转换为 Runnable 实例,该构造器的声明如下:

public FutureTask(Callable<V> callable)

该构造器使得我们能够方便地创建一个能够返回处理结果的异步任务 。 我们可以将任务的处理逻辑封装在一个 Callable 实例中,并以该实例为参数创建一个 FutureTask 实例 。由于 FutureTask 类实现了 Runnable 接口,因此上述构造器的作用就相当于将 Callable 实例转换为 Runnable 实例,而 FutureTask 实例本身也代表了我们要执行的任务 。 我们可以用 FutureTask 实例 (Runnable 实例)为参数来创建并启动一个工作者线程以执行相应的任务,也可以将 FutureTask 实例交给 Executor 执行(通过 Executor.execute(Runnable task)调用)。 FutureTask 类还实现了 Future 接口,这使得我们在调用 Executor.execute(Runnable task)这样只认 Runnable 接口的方法来执行任务的情况下依然能够获取任务的执行结果:一个工作者线程(可以是线程池中的一个工作者线程)负责调用 FutureTask.run()执行相应的任务,另外一个线程则调用 FutureTask.get()来获取任务的执行结果。因此, FutureTask 实例可被看作一个异步任务,它使得任务的执行和对任务执行结果的处理得以并发执行,从而有利于提高系统的并发性。
FutureTask 还支持以回调 (Callback) 的方式处理任务的执行结果。当 FutureTask 实例所代表的任务执行结束后, FutureTask.done()会被执行,FutureTask.done()是个 protected方法, FutureTask 子类可以覆盖该方法并在其中实现对任务执行结果的处理。FutureTask.done()中的代码可以通过 FutureTask.get()涸用来获取任务的执行结果,此时由于任务已经执行结束,因此 FutureTask.get()调用并不会使得当前线程暂停。但是,由于任务的执行结束既包括正常终止,也包括异常终止以及任务被取消而导致的终止,因此FutureTask.done() 方法中的代码可能需要在调用 FutureTask.get() 前调用 FutureTask.isCancelled()来判断任务是否被取消,以免 FutureTask.get() 调用抛出 CancellationException异常(运行时异常)。

猜你喜欢

转载自blog.csdn.net/sinat_25991865/article/details/88044715
今日推荐