1 简介
- 使用继承方式的好处是方便传参,可在子类里面添加成员变量,通过 set 方法设置参数者通过构造器进行传递
- 使用 Runnable 方式,则只能使用主线程里面被声明为 final 变量
不好的地方是 Java 不支持多继承,若继承了 Thread 类,则子类不能再继承其它类 ,而 Runable接口则无该限制 。
Thread 类和 Runnable 接口都不允许声明检查型异常,也不能定义返回值。
没有返回值就有点麻烦,这两种方式都没办法拿到任务的返回结果,但FutureTask 可以!
不能声明抛出检查型异常则更麻烦一些。run()方法意味着必须捕获并处理检查型异常。即使小心地保存了异常信息(在捕获异常时)以便稍后检查,但也不能保证这个 Runnable 对象的所有使用者都读取异常信息。
可以修改Runnable实现的getter,让它们都能抛出任务执行中的异常。但这种方法除了繁琐也不是十分安全可靠,你不能强迫使用者调用这些方法,程序员很可能会调用join()方法等待线程结束然后就不管了。
但是现在不用担心了,以上的问题终于在1.5中解决了。
Callable接口和Future接口的引入以及他们对线程池的支持优雅地解决了这两个问题。
2 案例
FutureTask 相关组件如何使用的=
3 Callable
Callable函数式接口定义了唯一方法 - call()。可以在Callable的实现中声明强类型的返回值,甚至抛异常。
利用call()直接返回结果,省去读取值时的类型转换。
- 定义
- 返回值是个泛型,使用时,不会直接使用 Callable,而是和 FutureTask 协同。
4 Future
- Callable 可以返回线程的执行结果,在获取结果时,就需用到Future接口
- Future是 Java5 中引入的接口,当提交一个Callable对象给线程池时,将得到一个Future对象,并且它和传入的Callable有相同的结果类型声明。
它取代了Java5 前直接操作 Thread 实例做法。以前,不得不用Thread.join()或Thread.join(long millis)等待任务完成。
Future表示异步计算的结果,提供了一些方法来检查计算是否完成,等待其完成以及检索计算结果。
只有在计算完成时才可以使用get方法检索结果,必要时将其阻塞,直到准备就绪。
取消是通过cancel方法执行的。
提供了其他方法来确定任务是正常完成还是被取消。一旦计算完成,就不能取消计算。
如果出于可取消性的目的使用Future而不提供可用的结果,则可以声明Future <?>形式的类型,并作为基础任务的结果返回null。
4.1 Future API
4.1.1 cancel - 尝试取消执行任务
当任务处于不同状态时,该方法有不同响应:
任务已完成 / 已取消 / 由于某些其他原因无法被取消
该尝试会直接失败
尝试成功,且此时任务尚未开始
可以取消成功
任务已开始
mayInterruptIfRunning 参数确定是否可以中断执行该任务的线程以尝试停止该任务。
此方法返回后,对 isDone 的后续调用将始终返回 true。若此方法返回 true,则随后对 isCancelled 的调用将始终返回 true。
4.1.2 isCancelled - 是否被取消
如果此任务在正常完成之前被取消,则返回true.
4.1.3 isDone - 是否完成
如果此任务完成,则返回true。
完成可能是由于正常终止,异常或取消引起的,在所有这些情况下,此方法都将返回true。
4.1.4 get - 获取结果
等待任务完成,然后获取其结果。
若:
- 任务被取消,抛 CancellationException
- 当前线程在等待时被中断,抛 InterruptedException
- 任务抛出了异常,抛 ExecutionException