FutureTask的测试使用和方法执行分析

news2025/1/24 4:53:34

FutureTask类图如下
在这里插入图片描述

java.util.concurrent.FutureTask#run run方法执行逻辑如下

 public void run() {
        if (state != NEW ||
            !RUNNER.compareAndSet(this, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

state说明:

  • NEW:新任务的初始状态;
  • COMPLETING:当任务被设置结果时,处于COMPLETING状态,是一个中间状态;
  • NORMAL:表示任务正常结束;
  • EXCEPTIONAL:表示任务因异常而结束;
  • CANCELLED:任务还未执行完成之前就调用了cancel方法,任务处于CANCELLED;
  • INTERRUPTING:当任务调用cancel(true)中断程序时,任务处于INTERRUPTING状态,是一个中间状态;
  • INTERRUPTED:任务调用cancel(true)中断程序时会调用interrupt()方法中断线程运行,任务状态由INTERRUPTING转变为INTERRUPTED;

代码逻辑说明:

  • 如果不是新建状态或者已经在运行中,则直接返回
  • 否则执行如下:
  1. 取FutureTask内部的Callable,不是空且是新建状态就去执行
  2. 执行成功失败记录
    • 成功,记录结果,状态最后为:NORMAL
    • 失败,记录异常, 状态最后为:EXCEPTIONAL
  3. 最后会并完成任务,会执行java.util.concurrent.FutureTask#finishCompletion(最后内部的Callable会设置为null)
  private void finishCompletion() {
// assert state > COMPLETING;
    for (WaitNode q; (q = waiters) != null;) {
        if (WAITERS.weakCompareAndSet(this, q, null)) {
            for (;;) {
                Thread t = q.thread;
                if (t != null) {
                    q.thread = null;
                    LockSupport.unpark(t);
                }
                WaitNode next = q.next;
                if (next == null)
                    break;
                q.next = null; // unlink to help gc
                q = next;
            }
            break;
        }
    }

    done();

    callable = null;        // to reduce footprint
}

唤醒下一个线程,并从等待队列中移除掉。


get超时方法

 public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
    if (unit == null)
        throw new NullPointerException();
    int s = state;
    if (s <= COMPLETING &&
        (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
        throw new TimeoutException();
    return report(s);
}
 /**
     * Awaits completion or aborts on interrupt or timeout.
     *
     * @param timed true if use timed waits
     * @param nanos time to wait, if timed
     * @return state upon completion or at timeout
     */
    private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
        // The code below is very delicate, to achieve these goals:
        // - call nanoTime exactly once for each call to park
        // - if nanos <= 0L, return promptly without allocation or nanoTime
        // - if nanos == Long.MIN_VALUE, don't underflow
        // - if nanos == Long.MAX_VALUE, and nanoTime is non-monotonic
        //   and we suffer a spurious wakeup, we will do no worse than
        //   to park-spin for a while
        long startTime = 0L;    // Special value 0L means not yet parked
        WaitNode q = null;
        boolean queued = false;
        for (;;) {
            int s = state;
            if (s > COMPLETING) {
                if (q != null)
                    q.thread = null;
                return s;
            }
            else if (s == COMPLETING)
                // We may have already promised (via isDone) that we are done
                // so never return empty-handed or throw InterruptedException
                Thread.yield();
            else if (Thread.interrupted()) {
                removeWaiter(q);
                throw new InterruptedException();
            }
            else if (q == null) {
                if (timed && nanos <= 0L)
                    return s;
                q = new WaitNode();
            }
            else if (!queued)
                queued = WAITERS.weakCompareAndSet(this, q.next = waiters, q);
            else if (timed) {
                final long parkNanos;
                if (startTime == 0L) { // first time
                    startTime = System.nanoTime();
                    if (startTime == 0L)
                        startTime = 1L;
                    parkNanos = nanos;
                } else {
                    long elapsed = System.nanoTime() - startTime;
                    if (elapsed >= nanos) {
                        removeWaiter(q);
                        return state;
                    }
                    parkNanos = nanos - elapsed;
                }
                // nanoTime may be slow; recheck before parking
                if (state < COMPLETING)
                    LockSupport.parkNanos(this, parkNanos);
            }
            else
                LockSupport.park(this);
        }
    }
  • 判断如果是运行中,特定时间内就while(true)不断判断完成或异常; 中间有个细节( Thread.yield() : 自己在运行,尝试让出CPU )
  • 超时仍运行(即特定时间判断完后线程还是运行中)则抛出TimeoutException; 否则返回对应结果

返回结果

/**
* Returns result or throws exception for completed task.
 *
 * @param s completed state value
 */
@SuppressWarnings("unchecked")
private V report(int s) throws ExecutionException {
    Object x = outcome;
    if (s == NORMAL)
        return (V)x;
    if (s >= CANCELLED)
        throw new CancellationException();
    throw new ExecutionException((Throwable)x);
}

测试代码:

 public static void main(String[] args) throws InterruptedException {

        ExecutorService executorService = Executors.newSingleThreadExecutor();

        FutureTask<Integer> futureTask1 = new FutureTask(()->{
            try{
                System.out.println("task Run....");
                TimeUnit.SECONDS.sleep(3);
            }catch (Exception e){

            }
            System.out.println("task finish....");
            return 1;
        });

        System.out.println(futureTask1);
        executorService.submit(futureTask1);
        TimeUnit.SECONDS.sleep(1);
        futureTask1.cancel(false);
        System.out.println(futureTask1.toString());

        Integer a = null;
        try {
            a = futureTask1.get(2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException | TimeoutException e) {
            e.printStackTrace();
        }
        System.out.println(futureTask1);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1094635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【软考】9.4 图的概念/存储/遍历/最小生成树/拓扑/查找

《图》 图的存储&#xff08;顶点和边&#xff09; 邻接矩阵&#xff1a;适合边数较多的图&#xff0c;不易造成浪费无向图&#xff1a;不分方向&#xff1b;对称矩阵 邻接链表&#xff1a;顶点&#xff0c;边——>&#xff08;编号&#xff0c;权值&#xff09;&#xff1b…

二维数组的行指针与列指针

二维数组的行指针与列指针 笔记来源&#xff1a;懒猫老师-C语言-用指针访问二维数组&#xff08;指针与二维数组&#xff09; 声明&#xff1a;本文笔记来自bili懒猫老师&#xff0c;仅供学习参考 回顾一维数组 int a[3];//其中a或a[0]是数组首地址 //a1指向第二个元素的地址…

The SDK location is inside Studio install location 解决

The SDK location is inside Studio install location 解决 安装 Android Studio SDK 时提示&#xff1a;The SDK location is inside Studio install location 解决 问题&#xff1a; 由于 SDK 与 编辑器(Android Studio)的安装在同一目录下所以报错。 解决 你需要在 Andro…

五、RocketMQ发送顺序消息

顺序消息的应用场景 在有序事件处理、撮合交易、数据实时增量同步等场景下&#xff0c;异构系统间需要维持强一致的状态同步&#xff0c;上游的事件变更需要按照顺序传递到下游进行处理。 例如需要保证一个订单的生成、付款和发货&#xff0c;这三件事情是被顺序执行的。 如…

C# OpenVINO Det 物体检测

效果 耗时 elephant:89% Preprocess: 0.00ms Infer: 47.21ms Postprocess: 11.63ms Total: 58.84ms 项目 代码 using OpenCvSharp; using Sdcb.OpenVINO; using Sdcb.OpenVINO.Natives; using System; using System.Diagnostics; using System.Drawing; using System.Text; …

淘宝店铺订单详情接口,淘宝店铺订单列表数据,淘宝店铺订单物流接口,淘宝店铺订单线下发货接口-

淘宝店铺订单详情接口可以理解为淘宝开放平台&#xff08;Taobao Open Platform&#xff09;提供的API接口1。 该接口可以获取淘宝店铺的订单详情&#xff0c;包括订单号、买家昵称、收货人姓名、收货地址、邮编、电话、商品描述、价格等信息。开发者可以在淘宝开放平台注册一…

使用winUSB进行USB开发

什么是winUSB WinUSB是Windows操作系统提供的一种通用USB驱动程序&#xff0c;用于简化USB设备的开发和使用。它是一个用户模式驱动程序&#xff0c;可以在Windows XP及更高版本的操作系统上使用。WinUSB提供了一组API和工具&#xff0c;使开发人员能够与USB设备进行通信&…

C++11可变参数模板

文章目录 1.可变参数模板的介绍1.1C语言中的可变参数1.2C98/C11的类模板和函数模板1.3可变参数的函数模板1.4展开参数包递归展开初始化列表展开 2.可变参数模板的应用 1.可变参数模板的介绍 1.1C语言中的可变参数 1.2C98/C11的类模板和函数模板 C98/03&#xff0c;类模版和函…

Numpy(一)简介与基本使用

Numpy&#xff08;一&#xff09;简介与基本使用 一、Numpy简介 1.Numpy是一个运行速度非常快的数学库&#xff0c;主要用于数组计算 2.包含&#xff1a;N维数组对象ndarray、广播功能函数、整合C/C/Fortran代码工具、包含线性代数/傅里叶变换/随机数生成等功能 3.优点&…

ChatGPT快速入门

ChatGPT快速入门 一、什么是ChatGPT二、ChatGPT底层逻辑2.1 实现原理2.2 IO流程 三、ChatGPT应用场景3.1 知心好友3.2 文案助理3.3 创意助理3.4 角色扮演 一、什么是ChatGPT ChatGPT指的是基于GPT&#xff08;Generative Pre-trained Transformer&#xff09;模型的对话生成系…

python字典、列表排序,从简单到复杂

因工作原因&#xff0c;需要频繁对python字典(dict)、列表(list)等进行各种各样的排序&#xff0c;发现网上这块的资料又多又杂&#xff0c;尤其涉及到lambda的&#xff0c;让人觉得难以理解看不下去&#xff0c;因此写了这篇文章&#xff0c;从简单到复杂&#xff0c;配合例子…

【Eclipse】安装教程

首先打开官网&#xff1a;Eclipse Downloads | The Eclipse Foundation 这里我选择了下载最新版本 下载好后&#xff0c;双击下载的文件 &#xff0c;即可进入到安装页面 点击第一个进行安装&#xff1a; 最后安装成功&#xff01; 补充&#xff1a; 【Eclipse】安装JAVA EE插…

Jmter接口网站压力测试工具使用记录

1.首先下载Jmeter 官方地址&#xff1a;Apache JMeter - Apache JMeter™ 回到顶部 2.安装Jmeter 把下载的文件进行解压&#xff0c;产生如下目录&#xff1a; 打开bin文件夹下的jmeter.bat文件及进入程序的主界面窗体jmeter.log是日志文件。 主意&#xff1a;需要配置java环…

河北专升本(C语言)

目录 一&#xff1a;C语言的构成特点 二: 数据类型 三: 常量、变量、运算符及表达式 &#xff08;一&#xff09;标识符 &#xff08;二&#xff09;常量 &#xff08;三&#xff09;变量&#xff1a;其值可以改变的量 &#xff08;四&#xff09;各种类型数据混合运算 &…

打印编译程序固件的环境信息

在编译程序固件的时候&#xff0c;我们常常会有一个软件版本号&#xff0c;用来区分不同的版本&#xff0c;有时候又没变化软件版本号&#xff0c;重新发两个debug版本给测试验证&#xff0c;那我们就需要在程序中埋入一些环境信息&#xff0c;下面有两种方法来加入一下简单的信…

APP 备案公钥、签名 MD5、SHA-1、SHA-256获取方法。

公钥和 MD5 值可以通过安卓开发工具、Keytool、Jadx-GUI 等多种工具获取&#xff0c;最简单的就是以 jadx-gui 为例。 1.下载 jadx-gui 工具 &#xff0c;点击此处 下载 jadx-gui 工具。 2.下载完成后&#xff0c;解压压缩包&#xff0c;双击 jadx-gui-1.4.7.exe 运行。 3.…

Neo4j入门基础:CREATE,DELETE,SET,REMOVE(看不懂我直接吃...)

1. 创建节点 1.1 创建一个节点 create (s:student1)创建一个标签为student1的节点 1.2 创建多个节点 create (s2:student2),(s3:student3)同时创建两个节点&#xff0c;标签分别为&#xff1a;student2&#xff0c;student3 1.3 创建节点并附带&#xff08;多个&#xff0…

MAC上设置IDEA如何一个窗口打开多个项目,多个tab

1、IDEA一个窗口打开多个项目 如果你打开了多个项目、每次切换都要半天&#xff0c;想让项目都汇聚到top栏 点击 Window - Merge All Project Windows 即可 但是这样比较挫&#xff0c;每次打开新的项目都还是会重新打开一个IDEA窗口 so&#xff0c;如何设置项目在同一个窗口…

树模型(一)孤立森林

孤立森林&#xff08;Isolation Forest&#xff09;算法是西瓜书作者周志华老师的团队研究开发的算法&#xff0c;一般用于结构化数据的异常检测。 异常的定义 针对于不同类型的异常&#xff0c;要用不同的算法来进行检测&#xff0c;而孤立森林算法主要针对的是连续型结构化…

Junit单元测试之Maven项目集成Jacoco,查看覆盖率报告

关于单元测试以及本文Calculate类等内容&#xff0c;请见前述文章Junit单元测试_Joy T的博客-CSDN博客 要学Jacoco&#xff0c;首先要知道测试覆盖率是什么&#xff01; 测试覆盖率 测试覆盖率表示的是测试用例所能触及&#xff08;或“覆盖”&#xff09;的代码百分比。换句…