zoukankan      html  css  js  c++  java
  • 揭开Future的神秘面纱——任务执行

    前言

      此文承接之前的博文 解开Future的神秘面纱之取消任务 补充一些任务执行的一些细节,并从全局介绍程序的运行情况。

    系列目录

    任务的提交与执行

    任务提交到执行的流程

      

    前文我们已经了解到一些Future的实现细节,这里我们来梳理一下运行流程。注意:这里说的是提交(Submit),而不是执行(execute)

    (1)客户端创建一个线程任务,即一个Callable或Runnable对象。

    (2)客户端调用ExecutorService的submit方法,将任务提交给执行器。

    (3)ExecutorService的具体类会将submit委托给AbstractExecutorService(具体类的父类)。

    (4)父类submit方法将获取到的Runnable/Callable任务交由其内部方法newTaskFor进行包装。

    (5)newTaskFor方法将Runnable/Callable包装成FutureTask对象。

    (6)submit把包装好的FutureTask对象交由execute方法执行,此方法有ThreadPoolExecutor(具体类)提供。

    (6)submit方法返回FutreTask对象引用给客户端。

    任务提交为何能接收两种类型的接口?

    FutureTask接收到Runnable对象后,会利用适配器,将其适配为Callable对象进行使用。注意,Runnable适配后,返回值基本没什么意义,都是写死的。

      

    实际上很有意思的是,FutureTask只使用Callable对象(因为使用Future的初衷就是想要获取任务处理结果),而Executor的execute只接收Runnable对象(执行器只管执行任务)

     FutureTask

    FutureTask实际上相当于Runnable对象的装饰器,FutureTask的继承结构如图所示:

        

    我们知道Runnable定义了任务该做什么,Future定义了任务的控制操作,而RunnableFuture接口兼具这两个功能。

    Future就是实现这组操作的实现类,它也是Runnable的装饰器类,Runnable任务在经过其包装后,仍然还是Runnable,不影响其交给execute方法执行。而且他实现了Future接口,也就可以根据它对任务进行控制。

    FutureTask有哪些字段,用来做什么的?

      

    (1)state => 状态,用于基于状态的控制操作。

    • NEW  => 新建任务
    • COMPLETING => 正在完成,即任务已经被线程启动
    • NORMAL => 正常完成任务
    • EXCEPTIONAL => 任务因为异常而终止
    • CANCELLED => 任务已被取消,注意这里并不表示任务实际状态,即任务可能还在运行。
    • INTERRUPTING => 中断任务中
    • INTERRUPTD => 任务已被中断

    (2)callable => callable任务,实际被执行的任务

    (3)outcome => 执行结果

    (4)runner => 执行线程的引用,用来控制任务的执行。

    (5)waiters => 等待线程队列,当任务还未完成时,用于保存因为获取结果的而被阻塞的线程。

    FutureTask的状态变化

    (1)NEW -> COMPLETING -> NORMAL(任务正常执行到结束)

    (2)NEW -> COMPLETING -> EXCEPTIONAL(任务执行过程中出现异常)

    (3)NEW -> CANCELLED (任务被取消)

    (4)NEW -> INTERRUPTING -> INTERRUPTED (任务已经开始,尚未完成就被取消)

    FutureTask如何确定其执行线程的?

      任务的控制最主要的两个功能就是取消和获取结果。取消的操作,上一篇博文已经讲到了,获取结果将于下篇讲述。这里补充前篇的一些内容,也就是取消操作相关的细节,当时已经获知,要取消任务,实际上是通过中断任务的执行线程实现的,如图:

      FutureTask的cancel方法

      

    但是,这个runner是何时被赋值的,我当时并不清楚,查阅源码也没发现什么setRunner之类的代码。后来突然想到,只有在任务被执行的时候才能知道,它到底被哪个线程执行。于是才注意到了这段CAS的代码,(当时不太懂,所以就算看到了这段代码,也不明白)。意思就是说,如果当前对象的runner字段值为null,就将其设置为当前的执行线程。到这里,我们就有了此线程的引用。

      

      

    FutureTask到达ThreadPoolExecutor的execute之后,是什么情形?

      这里简要说一下,任务到达ThreadPoolExecutor之后,线程池会根据当前线程数量的情况进行处理,可能创建一个新线程来执行,或者加入到任务队列等待执行,再或者就是被线程池抛弃等等。

      相关细节可查看,我关于ThreadPoolExecutor的相关博文。

     

  • 相关阅读:
    Django 框架篇(四) : 视图(view)详解 及 路由系统(url)
    Django 框架篇(三) : Django之模板
    Django 框架篇(二) : 创建APP之视图函数; model(模型)系统操作数据库之ORM操作;
    Django 框架篇: 一. Django介绍; 二. 安装; 三. 创建项目;
    212
    redux:applyMiddleware源码解读
    react 反模式——不使用jsx动态显示异步组件
    angular 动态组件类型
    webpack2-webpack.config.js配置
    tdd:(react + mocha)环境配置
  • 原文地址:https://www.cnblogs.com/longfurcat/p/9902340.html
Copyright © 2011-2022 走看看