一:Runnable
函数式接口,实现类实现唯一线程方法run()即可
二:Thread
实现接口Runnable,扩展出系列线程守护、状态、中断、睡眠、阻塞等操作。需要注意一点该类实例启动线程时使用start()并非调用run()
三:Callable
JDK1.5提供另一个函数式接口,区别于Runnable最大点在于异常抛出与返回值获取。配合FutureTask使用
四:FutureTask
4.1 继承结构
4.2 状态标记
FutureTask中提供系列常量标记执行线程状态,具体含义如下表所示:
状态名称 | 状态数值 | 状态含义 |
---|---|---|
NEW | 0 | 刚创建未执行线程 |
COMPLETING | 1 | 线程执行完毕 |
NORMAL | 2 | 线程状态正常 |
EXCEPTIONAL | 3 | 线程异常 |
CANCELLED | 4 | 线程已经取消 |
INTERRUPTING | 5 | 线程中断 |
INTERRUPTD | 6 | 线程已经被中断 |
可能的状态切换,可以看出线程初始状态都是由NEW开始。不正常步骤为最后三个,表示取消、中断、执行异常。第一个代表执行正常
4.3 实例化构建
4.3.1 Callable
Callable比较简单,根据参数将属性callable设置即可,接下来看一下使用Runnable+result构建的FutureTask
4.3.2 Runnable + result
调用Executors静态方法callable(),注意该方法是返回一个Callable实例。但是最后return实例化的是一个RunnableAdaptor,接下来继续看该类是什么情况
明显RunnableAdapter是Executors一个静态内部类,实现Callable接口。该类使用属性task存储线程,call方法中调用线程方法run()后直接返回传入返回值
4.4 线程方法处理
1
校验线程状态,初始线程状态都为NEW
2
调用Callable实现类call(),获取返回值
3
成功set()将返回值存储到outcome属性
4
失败setException()将异常存储到outcome
5
outcome是FutureTask中Object类型属性
6
循环遍历等待线程节点链表,顺序唤醒线程
4.3 返回值获取
1
线程状态小于COMPLETING那就只能是NEW未执行完毕状态
2
处理线程未执行完毕,awaitDone()在for循环中添加线程等待节点与睡眠线程
3
线程中断检测,移除等待节点,抛出中断异常
4
线程状态大于COMPLETING能到达的线程状态只能是正常、异常、中断、取消这几种状态值都表示线程已经执行出结果。返回对应状态值即可
5
最关键的两个最后两个判断,根据get()重载等待时间,判断是否到达使用LockSupport完成线程阻塞
6
回到步骤一查看report(),到这里线程必定已经执行完毕,最后的结果只能是NOMAL、EXCPTIONAL、CANCELLED、INTERRUPTED四种,分别进行处理即可
4.4 中断与取消
cacel()参数标识将FutureTask置为中断亦或是取消,也就是对FutureTask实例对象更换不同状态
4.5 中断/完毕检测
两种检测方式isCalled()与isDone()都是根据状态判定,大于等于CANCELLED除了自身外只能是INTERRUPTED等。而不等于NEW就代表已经执行完毕的状态
五:FutureTask总结
牢记几种状态表示含义
- 使用内部类WaitNode记录阻塞等待线程
- run()中执行call()将result存储到outcome,并调用finishCompletion()唤醒等待线程
- get()中会根据FutureTask状态进行线程睡眠亦或是返回,借助LockSupport