自定义封装异步任务组件,实现FutureTask功能

2023-10-31

  • FutureTask

在 JDK1.8 后的异步编排API中的CompletableFuture,提供了 异步任务的成功回调、异常回调。

public class FutureTaskTest {

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

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return UUID.randomUUID().toString();
        });

        future.thenAccept((s) -> {
            System.out.println("异步任务的返回值" + s);
        });

        future.exceptionally((ex) -> {
            ex.printStackTrace();
            return null;
        });


        Thread.sleep(5000);

    }

}

启动一个异步任务后,就相当于启动了一个线程,给这个异步对象设置回调方法,那么当异步任务运行结束或者出现异常时会自动调用相关的回调。

  • 自定义AsyncTask实现 异步任务回调
public class AsyncTest {

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

        AsyncTask<String> asyncTask = new AsyncTask<>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("开始处理数据");
                Thread.sleep(3000);
                String s = UUID.randomUUID().toString();
                System.out.println("数据计算完成");
                return s;
            }
        });

        asyncTask.run();

        Thread.sleep(5000);

        asyncTask.thenError((ex) -> {
            ex.printStackTrace();
        });

        asyncTask.thenSuccess((s) -> {
            System.out.println("任务数据:" + s);
        });

        System.out.println("主线程结束");

    }

}

class AsyncTask<T>{

    private Callable<T> task;

    private T value;

    private Exception e;

    private Consumer<T> successConsumer;

    private Consumer<? super Exception> exConsumer;

    private Thread thread;

    public AsyncTask(Callable<T> task){
        this.task = task;
    }

    public void run(){
        this.thread = new Thread(() -> {
            try {
                value = task.call();
                if (successConsumer != null){
                    successConsumer.accept(value);
                }
            } catch (Exception e) {
                this.e = e;
                if (exConsumer != null){
                    exConsumer.accept(e);
                }
            }
        });
        this.thread.start();
    }

    public void thenSuccess(Consumer<T> consumer){
        this.successConsumer = consumer;
        if (this.thread != null && !this.thread.isAlive() && e == null){
            consumer.accept(value);
        }
    }

    public void thenError(Consumer<? super Exception> consumer){
        this.exConsumer = consumer;
        if (this.thread != null && !this.thread.isAlive() && e != null){
            consumer.accept(e);
        }
    }

}

异步任务回调 就是想让线程运行完成后执行其他线程设置的回调方法。
这里通过 thenSuccess 设置异步线程的回调方法 ,然后通过以下代码去判断是否已经设置了异步回调。

 if (successConsumer != null){
   successConsumer.accept(value);
 }

这里还有一个问题,主线程是先调用了run方法,再调用了thenSuccess方法,如果run方法和thenSuccess方法之前的执行时间超过了异步任务的执行时间。

在这里插入图片描述

避免这种问题的解决办法有2中。

  1. 在run之前先调用thenError 、thenSuccess 设置好回调后,再调用run。
    由于在开启线程之前就已经设置好回调了,自然不用担心。

  2. 在thenError、thenSuccess 方法内判断线程的状态,如果线程的isAlive方法返回false,则说明线程已经运行完了,在运行中的线程状态是true,所以,将线程的返回值以及异常保存起来,在调用 thenError、thenSuccess 方法 时,判断线程如果运行完成(调用了start方法的线程状态会是true),这个时候说明还没有执行回调,则拿到返回值后调用回调方法即可。

 if (this.thread != null && !this.thread.isAlive() && e == null){
            consumer.accept(value);
        }
  • 泛型

关于泛型的理解,泛型类可以想象成一个翁,翁就是一个容器,可以装各种各样的东西,每个翁都是如此,但是为了方便装的东西后续可以快速找到,就给每一个翁贴上一个标签,例如第一个翁只装钥匙,第二个翁只装杯子等等,这样从翁中拿出来的时候也只会是放进入的东西。泛型就相当于翁的一个标签,标识着此翁装配的东西,

一个翁也就是是带泛型的Java对象,在当作参数传递的过程中翁上的标签也是会传递的,Java编译器会自动检查带泛型的对象返回的类型以及当作参数传入的对象类型,例如 stream的map方法在使用lambda返回时 会自动推断返回值类型,如果接受的类型不匹配,编译器会报错,再比如使用lambda表达式定义入参时,无需指定参数类型,如果泛型类型是String类型,那就调不了其他类的方法,这也是有编译器保证的,这就是泛型的自动推断和传递。

有的实例方法需要的参数也是带着泛型的,例如AsyncTask中的

    public void thenSuccess(Consumer<T> consumer){
        this.successConsumer = consumer;
        if (this.thread != null && !this.thread.isAlive() && e == null){
            consumer.accept(value);
        }
    }

    public void thenError(Consumer<? super Exception> consumer){
        this.exConsumer = consumer;
        if (this.thread != null && !this.thread.isAlive() && e != null){
            consumer.accept(e);
        }
    }

例如thenSuccess 方法需要一个Consumer 实例,而这个实例也是需要带标签的,那这个标签是什么呢?就是取决于当前对象的标签,例如我有一个翁,标签是 钥匙,那我需要一个处置东西的工具、而这个处置东西的工具也可以打标签,例如可以处置杯子、处置木头、处置钥匙等,那这个地方的意思就是我需要一个Consumer类型的对象,这个对象的标签是T,而T是哪里来的,T是在创建当前对象的时候定义好的,也就是类似常说的出厂设置,这个实例在创建的时候就知道自己的泛型,即 某个翁在制造好出厂的时候就打好标签了。那自然 此对象在当作参数传递时,编译器也会自动检查标签是否与某个方法参数相匹配等等。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

自定义封装异步任务组件,实现FutureTask功能 的相关文章

  • Java - 因内存不足错误而关闭

    关于如何最好地处理这个问题 我听到了非常矛盾的事情 并且陷入了以下困境 OOME 会导致一个线程崩溃 但不会导致整个应用程序崩溃 我需要关闭整个应用程序 但不能 因为线程没有剩余内存 我一直认为最佳实践是让它们离开 这样 JVM 就会死掉
  • Android 中的列表(特别是 RecyclerView 和 CardView)如何工作

    请原谅我问这个问题 但我是 Android 开发新手 尽管我正在尝试了解developer android com 网站上的基础知识 但大多数示例 即使他们说它们是为 Android Studio 构建的 尚未设置为使用 Gradle 因此
  • 如何强制jar使用(或jar运行的jvm)utf-8而不是系统的默认编码

    我的Windows默认编码是GBK 而我的Eclipse完全是utf 8编码 因此 在我的 Eclipse 中运行良好的应用程序崩溃了 因为导出为 jar 文件时这些单词变得不可读 我必须在 bat 文件中写入以下行才能运行该应用程序 st
  • HAProxy SSL终止+客户端证书验证+curl/java客户端

    我希望使用我自己的自签名证书在 HAProxy 上进行 SSL 终止 并使用我创建的客户端证书验证客户端访问 我通过以下方式创建服务器 也是 CA 证书 openssl genrsa out ca key 1024 openssl req
  • 如何将jscrollpane添加到jframe?

    我有以下源代码 有人可以给我建议如何将 jscrollpane 添加到 jframe 上吗 我尝试了几次将其添加到 jframe 但没有任何进展 它甚至没有显示 public class Form3 JFrame jframe new JF
  • 将SQL数据引入jquery availabletag

    我正在尝试制作自动完成文本框 但如何将 SQL 数据包含到 jquery 可用标记并循环它 我无法根据以下代码执行该功能 任何帮助 将不胜感激 谢谢 这是我的预期输出 预期结果演示 http jsfiddle net VvETA 71 jq
  • 在 Struts 2 中传递 URL 参数而不使用查询字符串

    我想使用类似的 URL host ActionName 123 abc 而不是像这样传递查询字符串 host ActionName parm1 123 parm2 abc 我怎样才能在 Struts 2 中做到这一点 我按照下面的方法做了
  • 您建议使用哪种压缩(GZIP 是最流行的)servlet 过滤器?

    我正在寻找一个用于大容量网络应用程序的 GZIP servlet 过滤器 我不想使用容器特定的选项 要求 能够压缩响应负载 XML Faster 已在大批量应用的生产中得到验证 应适当设置适当内容编码 跨容器移植 可选择解压缩请求 谢谢 我
  • 如何检测图像是否像素化

    之前有人在 SO 上提出过这样的问题 在Python中检测像素化图像 https stackoverflow com questions 12942365 detecting a pixelated image in python还有关于q
  • 在 Java 中通过 XSLT 分解 XML

    我需要转换具有嵌套 分层 表单结构的大型 XML 文件
  • 如何删除日期对象的亚秒部分

    当 SQL 数据类型为时间戳时 java util Date 存储为 2010 09 03 15 33 22 246 如何在存储记录之前将亚秒设置为零 例如 在本例中为 246 最简单的方法是这样的 long time date getTi
  • 通过 appassembler-maven-plugin 生成的脚本无法在 Spring Boot 应用程序中找到主类

    我使用 appassembler maven plugin 生成的启动脚本有问题 我有一个基本的 spring boot 应用程序 只有一个类 SpringBootApplication public class ScriptDemoApp
  • 用于缓存的 Servlet 过滤器

    我正在创建一个用于缓存的 servlet 过滤器 这个想法是将响应主体缓存到memcached 响应正文由以下方式生成 结果是一个字符串 response getWriter print result 我的问题是 由于响应正文将不加修改地放
  • Karaf / Maven - 无法解决:缺少需求 osgi.wiring.package

    我无法在 Karaf 版本 3 0 1 中启动捆绑包 该包是使用 Maven 构建的并导入gson http mvnrepository com artifact com google code gson gson 2 3 1 我按照要求将
  • 避免 Java 中的重复导入:继承导入?

    有没有办法 继承 导入 Example 常见枚举 public enum Constant ONE TWO THREE 使用此枚举的基类 public class Base protected void register Constant
  • 我可以限制分布式应用程序发出的请求吗?

    我的应用程序发出 Web 服务请求 提供商处理的请求有最大速率 因此我需要限制它们 当应用程序在单个服务器上运行时 我曾经在应用程序级别执行此操作 一个对象跟踪到目前为止已发出的请求数量 并在当前请求超出允许的最大负载时等待 现在 我们正在
  • 禁用 Android 菜单组

    我尝试使用以下代码禁用菜单组 但它不起作用 菜单项仍然启用 你能告诉我出了什么问题吗 资源 菜单 menu xml menu menu
  • ArrayList.clear() 和 ArrayList.removeAll() 有什么区别?

    假如说arraylist定义为ArrayList
  • 将对象从手机共享到 Android Wear

    我创建了一个应用程序 在此应用程序中 您拥有包含 2 个字符串 姓名和年龄 和一个位图 头像 的对象 所有内容都保存到 sqlite 数据库中 现在我希望可以在我的智能手表上访问这些对象 所以我想实现的是你可以去启动 启动应用程序并向左和向
  • 即使调整大小,如何获得屏幕的精确中间位置

    好的 这个问题有两部分 当我做一个JFrame 并在其上画一些东西 即使我将宽度设置为 400 并使其在一个项目击中它时 当然 允许项目宽度 它会反弹回来 但由于某种原因 它总是偏离屏幕约 10 个像素 有没有办法解决这个问题 或者我只需要

随机推荐

  • metric_logger小解

    今天看见这个一个函数metric logger 通过搜索资料发现他是utils中的一个MetricLogger类 可称它为度量记录器 因为这种都是自定义的 那我只说说我遇见的这个趴 我们先来看看他初始化里有什么 def init self
  • VMware14安装虚拟机出错——Intel VT-x处于禁用状态

    解决方法 进入BIOS 模式中 开启Intel VT x 具体步骤 win10 1 打开设置 搜索 高级启动 选择更改高级启动选项设置 然后点击立即启动 2 启动后 在蓝屏界面中选择疑难解答 gt 高级选项 gt UEFI固件设置 gt 选
  • 【matlab图像处理】插值方法

    中国史之 懿王攻犬戎 周懿 yi 王攻打犬戎的战争 周懿王在位时期 西周衰弱 戎族不断入侵周朝 一度打到镐 今陕西西安 岐 今陕西岐县 等地 懿王被迫迁都槐里 今陕西兴平县 周懿王派虢 guo 公率军北伐犬戎 企图收复失地 但不幸战败 来源
  • 抽象类、模板方法

    抽象类理解为一种模板 模板模式 使用 package com example demo author dc version 1 0 date 2023 03 28 12 55 public abstract class DayPlan pu
  • PMOS开关管的选择与电路图

    中心议题 探讨 解决方案 选用N沟道还是P沟道 确定额定电流 确定热要求 首先要进行MOSFET的选择 MOSFET有两大类型 N沟道和P沟道 在功率系统中 MOSFET可被看成电气开关 当在N沟道MOSFET的栅极和源极间加上正电压时 其
  • centos7 配置网络_linux入门系列11--Centos7网络服务管理

    通过前面文章的学习已经掌握了Linux系统配置管理的知识 本文讲解Centos7网络配置知识 Linux要对外提供服务 需要保证网络通信正常 因此需要正确配置网络参数 本文将讲解如何使用Network Manager配置网络参数 管理网络会
  • MATLAB中复数矩阵的转置、共轭及共轭转置

    参考博客 https blog csdn net zhaozhichenghpu article details 79162287 MATLAB中生成一个复数矩阵 MATLAB中复数矩阵的共轭用conj A MATLAB中复数矩阵的转置 A
  • 安卓USB模块源码分析(一)- 准备

    介绍USB服务在Android服务体系中的位置 源码的位置及使用AndroidStudio 查看USB模块FWK的配置方式 Windows环境准备 WSL2安装及AOSP源码下载编译 shimo im 安卓服务概览 Android 主要有如
  • os.walk()的使用方法

    os walk 主要用来扫描某个指定目录下所包含的子目录和文件 这篇文章将通过几个简单的例子来说明python中os walk 的使用方法 一 从上到下 遍历目录 该文件夹 和子目录 子文件夹 以及文件 txt等 假设我们的test文件夹有
  • 如何在JavaScript中实现继承?

    聚沙成塔 每天进步一点点 专栏简介 原型链继承 借用构造函数继承 构造函数继承 组合继承 原型式继承 寄生式继承 寄生组合式继承 写在最后 专栏简介 前端入门之旅 探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航
  • 内核模式代码签名走查(四)

    如何禁用测试计算机上的强制签名 在驱动程序开发的早期阶段 开发人员签署每个构建都可能很麻烦 因为这个原因 WindowsVista提供了几个方式来临时禁用内核模式代码签名实施 以便测试计算机可以安装和加载未签名的驱动程序 附加一个内核调试器
  • Java语言程序设计(一)选择题

    1 1 如下哪个是 Java中的标识符 A public B super C 3number D width 2 如下哪个是 Java中的标识符 A fieldname B super C 3number D number 3 已知如下定义
  • Linux IO协议栈框图

    Linux IO协议栈框图 来源 http www thomas krenn com en oss linux io stack diagram linux io stack diagram v0 1 pdf
  • sqli-labs-master sql注入靶场(10、11、12)

    sqli labs master sql注入靶场 10 12 pass 10 首先 这题用sqlmap跑不出来 sqlmap提示我们这题是时间盲注 无论我们输入什么 不管对错页面都是You are in 我们用sleep函数来判断对错 如果
  • [工业互联-3]:工业有线互联总线之工业以太网总线

    目录 第1章 工业以太网概述 1 1 概述 1 2 工业以太网与普通以太网的比较 1 3 以太网在工业控制领域中应用的优势 1 4 工业以太网与其他工业互联总线的比较 第2章 工业以太网网络部署 第3章 工业以太网网络协议栈 3 1 传统以
  • LTspice introduction - 2 LTspice的界面

    LTspice的界面主要有两个 Schematic Capture和Waveform Viewer Schematic Capture 它主要是用来画电路图的 画完电路图之后 添加一些dot 命令同时选择一些仿真的参数 点击执行 Run W
  • dell服务器维护软件,Dell服务器硬件,RAID等查询和维护软件OMSA

    Dell服务器查询和维护软件OMSA OMSA OpenManageServerAdministrator 是Dell主机的硬件检测和维护软件 OMSA OpenManage 下载地址 http linux dell com repo ha
  • Golang 单元测试

    想要测试Go代码需要依赖go test命令 需注意如下事项 在包目录内所有测试文件必须以 test go结尾 go build不会把这些测试文件编译到最终的可执行文件中 在 test go文件中 单元测试函数的名字须以TestXxxx的形式
  • git: 如何减少.git文件的大小?

    1 起因 使用git储存本地笔记时 没有注意到其中包含的视频文件 avi 大约3个 每个100MB 将其也添加到git的历史记录中 git add git commit 虽然之后删除了视频文件本身 但其提交记录永久的留在了 git中 被gi
  • 自定义封装异步任务组件,实现FutureTask功能

    FutureTask 在 JDK1 8 后的异步编排API中的CompletableFuture 提供了 异步任务的成功回调 异常回调 public class FutureTaskTest public static void main