之前介绍了线程池相关的对象,Runable Callable与Future,下面介绍FutureTask的作用,它的特性是怎样的呢?
FutureTask特点
先看FutureTask的类图:
![957c469cb9589744869b07decec61aae.png](https://i-blog.csdnimg.cn/blog_migrate/19d00dcb6f446ff421a615e987e7ae91.jpeg)
从上图我们可以看到FutureTask实现了RunableFuture接口,同时RunableFuture又继承Future,Runable接口,也就是说FutureTask具备Runbale的run方法执行异步任务,也可以像Future一样能够控制任务的执行
内部成员变量
![3e05de954603f01ef5fb25cd9b252468.png](https://i-blog.csdnimg.cn/blog_migrate/a6ea3fdcdeaf8ab4d63c839f580f539c.jpeg)
状态信息分为:
NEW:任务新建; COMPLETING:任务即将完成;NORMAL:正常执行结束; EXCEPTIONAL:任务出现异常
CANCELLED:任务取消,INTERRUPTING:任务中断中 ,INTERRUPTED:任务已中断。
状态转换的序列:
NEW -> COMPLETING -> NORMALNEW -> COMPLETING -> EXCEPTIONALNEW -> CANCELLEDNEW -> INTERRUPTING -> INTERRUPTED
其他变量:
![60dfa65d8c1fdcce803c6c8f8621e65e.png](https://i-blog.csdnimg.cn/blog_migrate/44c882bbbbc0bd6b3a2a49951a2ac4b1.jpeg)
核心方法
构造方法:FutureTask(Callable<V> callable)和FutureTask(Runnable runnable, V result),接收callable和Runable,和结果result。
run():
![deb70b3b0f583c8d8e0320d752d0b4bc.png](https://i-blog.csdnimg.cn/blog_migrate/5e6366a5f0a1fa43c627b3d069b8f88d.jpeg)
主要的流程:如果当前状态不是NEW,或者调用CAS方法,判断RUNNER为null的话,都直接返回读取Callable 变量然后校验状态,执行call方法。如果执行call()的过程中发生异常,就调用设置异常信息,如果执行成功,则将执行set(result),设置结果如果业务逻辑异常,则调用setException方法将异常对象赋给outcome,并且更新state值最后会将runner设置为null,判断状态信息如果是INTERRUPTING,则表示正在被中断,交出线程执行权,让其他线程执行get()和get(long timeout, TimeUnit unit)
![7967ff845095b7c44e0e44c1510c48dd.png](https://i-blog.csdnimg.cn/blog_migrate/7d04a0de219f65b42307dfbc6587f788.jpeg)
这个跟future的含义一致,get()阻塞等待,get(long timeout, TimeUnit unit),阻塞特定的时间。其中主要分析下awaitDone(false, 0L)这个方法的具体逻辑:
![ad969617024938a24ca1485bea715777.png](https://i-blog.csdnimg.cn/blog_migrate/ec1fe25edb066748a6f9706e1661dbef.jpeg)
这是一个循环,如果当前线程被打断那么抛出异常,如果没有则取出状态信息s,如果s > COMPLETING,表示任务已经执行结束,或者出现异常结束,那么将等待节点中队列设置为null。s==COMPLETING 那么让出线程执行,如果等待节点q为null,则创建节点,并且将它插入到等待队列中,之后判断timed是否等待实现,如果是则计算具体时间执行LockSupport.parkNanos(this, nanos),等待具体的时间,否则LockSupport.parkNanos(this),进入一直阻塞状态。cancel(boolean mayInterruptIfRunning)1.如果子任务还没有执行,那么该任务执行停止,如果子任务已经执行,且mayInterruptIfRunning=true,那么执行子任务的线程也会被中断
finishCompletion()
不管是什么样的任务,无论取消还是其他,最后都会调用finishCompletion()方法具体应用实例:
一个能够有控制的异步任务:
![60ecb118e8bce1e15ffb1a104e614fd4.png](https://i-blog.csdnimg.cn/blog_migrate/b435563092c5ac06f8fef1e43444a0fc.jpeg)
以上总结:
FutureTask作为一个可以控制的异步任务的存在,是对Runable实现一种继承和扩展,在这里我们熟悉它的一些用法和应用场景,对内部方法进行学习。多接口的继承是我们日后开发设计中需要掌握的
欢迎关注我的百家号,java菜鸟到专家