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

news2024/9/25 21:21:34
  • 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是在创建当前对象的时候定义好的,也就是类似常说的出厂设置,这个实例在创建的时候就知道自己的泛型,即 某个翁在制造好出厂的时候就打好标签了。那自然 此对象在当作参数传递时,编译器也会自动检查标签是否与某个方法参数相匹配等等。

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

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

相关文章

kodi的IPTV直播源爬取

安装了kodi的IPTV插件后&#xff0c;就能看电视&#xff0c;但是网上的直接源不太稳定。想起家里的有个魔百盒hm201是可以看电视和点播&#xff0c;就想通过爬取魔百盒里的直播源实现家里的打造自己基本稳定直播源&#xff0c;实现全屋的电视自由。 原文地址&#xff1a; IPTV直…

U-net网络学习记录

U-net网络 本质上是一个用于图像分割的神经网络 输入是一幅图&#xff0c;输出是目标的分割结果。继续简化就是&#xff0c;一幅图&#xff0c;编码&#xff0c;或者说降采样&#xff0c;然后解码&#xff0c;也就是升采样&#xff0c;然后输出一个分割结果。根据结果和真实分…

全球顶尖开源项目相聚外滩大会,绘制国际化开源生态新蓝图

在科技快速发展的当下&#xff0c;开放协作已成为技术创新的催化剂。在全球范围内&#xff0c;开源也是科技交流的永恒主题。 9月7日&#xff0c;2023外滩大会开源分论坛在上海举行。本次论坛由蚂蚁集团主办&#xff0c;以“打造国际化的开源开放创新生态”为主题&#xff0c;…

# 如何使用 GitHub Copilot 发送 Tweet(译)

文章目录 首先&#xff0c;什么是 GitHub Copilot为什么我使用GitHub Copilot 发送 Tweet&#xff1f;理由 1理由 2理由 3 它对你来说有什么价值&#xff1f;如何使用 Copilot 发送推文步骤一&#xff1a;注册 Twitter 开发者账户步骤二&#xff1a;在 Twitter 开发者平台创建应…

如何评估以及优化谷歌ads

在广告投放一段时间后&#xff0c;应该对广告的效果有所了解。如果您的目标是增加销量和网站流量&#xff0c;米贸搜谷歌推广建议请考虑以下问题&#xff1a; 1.哪些关键字为广告带来的点击最多&#xff1f; 2.客户进行搜索时使用的是何种设备&#xff1f;他们来自何处&#xf…

vue知识点————插槽 slot

slot 插槽 在父组件中引用的子组件 在父组件中写入百度 可在子组件slot插槽中展示出 父组件 <template><div id"app"><child url"https://www.baidu.com">百度</child></div> </template><script> import chil…

达梦控制台还原报错“管道失败”

达梦数据库控制台还原报错“管道失败” 环境 主机操作系统&#xff1a;windows10 profession 达梦数据库版本&#xff1a;达梦7 问题背景 全新安装达梦7数据库后&#xff0c;创建数据库实例&#xff0c;需要恢复往期bat备份。在控制台配置指定搜索目录后&#xff0c;获取备份时…

功率放大器在扫描显微镜中的应用有什么

功率放大器在扫描显微镜中起到了至关重要的作用。扫描显微镜是一种高分辨率的显微镜技术&#xff0c;它能够以极高的精度观察和研究样品的表面形貌和结构特征。而功率放大器则能够提供所需的信号增益&#xff0c;使得扫描显微镜能够获得更加清晰、细致的图像。 功率放大器可以帮…

TLS协议深度解析:挖掘现代网络安全防御的底层技术

正常简单的通讯 1、服务器生成一对密钥&#xff0c;公钥A、私钥A 2、浏览器请求服务器时&#xff0c;服务器把公钥A传给浏览器 3、浏览器随机生成一个对称加密的密码S&#xff0c;用公钥A加密后传给服务器 4、服务器接收后&#xff0c;用私钥A解密&#xff0c;得到密钥S 5、浏…

学习心得08:OpenGL

我是想学习一下如何编程&#xff0c;这本书大多介绍的是原理。这两个完全是一回事。所以我又买了另外一本看看。

【Apollo学习笔记】——规划模块TASK之PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER(二)

文章目录 TASK系列解析文章OptimizeByNLP1.get_nlp_info()定义问题规模2.get_bounds_info()定义约束边界约束3.get_starting_point()定义初值4.eval_f()求解目标函数5.eval_grad_f()求解梯度6.eval_g()求解约束函数7.eval_jac_g()求解约束雅可比矩阵8.eval_h()求解黑塞矩阵9. f…

2023年9月CDGA/CDGP数据治理认证考试报名,找弘博创新

据DAMA中国官方网站消息&#xff0c;2023年度第三期DAMA中国CDGA和CDGP认证考试定于2023年9月23日举行。 报名通道现已开启&#xff0c;相关事宜通知如下&#xff1a; 考试科目: 数据治理工程师(CertifiedDataGovernanceAssociate,CDGA) 数据治理专家(CertifiedDataGovernanc…

四年级上册思维导图怎么绘制?简单漂亮绘制方法分享

四年级上册思维导图怎么绘制&#xff1f;思维导图是一种非常实用的工具&#xff0c;它可以帮助我们将复杂的想法和信息以图形化的方式呈现出来&#xff0c;让我们更加清晰地理解问题&#xff0c;并且更加容易地进行思考和决策。如果你需要绘制思维导图的话&#xff0c;那么今天…

抖店开通后要做的基础搭建,店铺快速起店的关键,建议认真看完

我是王路飞。 你是不是以为开通抖店之后&#xff0c;就没啥事了&#xff0c;可以直接选品上架了&#xff1f; 错了&#xff01; 在你选品上架之前&#xff0c;还有一步非常关键&#xff0c;就是店铺的基础搭建。 如果一些基础功能你没开通、设置没做好的话&#xff0c;是会…

C高级 第二天 shell指令

写一个1.sh脚本&#xff0c;将以下内容放到脚本中&#xff1a; 在家目录下创建目录文件&#xff0c;dir 在dir下创建dir1和dir2 把当前目录下的所有文件拷贝到dir1中 把当前目录下的的所有脚本文件拷贝到dir2中 把dir2打包并压缩为dir2.tar.xz 再把dir2.tar.xz移动到dir1…

buuctf web 前5题

目录 一、[极客大挑战 2019]EasySQL 总结&#xff1a; 二、[极客大挑战 2019]Havefun 总结&#xff1a; 三、[HCTF 2018]WarmUp 总论&#xff1a; 四、[ACTF2020 新生赛]Include 总结&#xff1a; 五、[ACTF2020 新生赛]Exec 总结&#xff1a; 一、[极客大挑战 2019]…

leetcode897. 递增顺序搜索树(java)

递增顺序搜索树 题目描述中序遍历代码演示 递归专题 题目描述 难度 - 简单 LC - 897. 递增顺序搜索树 给你一棵二叉搜索树的 root &#xff0c;请你 按中序遍历 将其重新排列为一棵递增顺序搜索树&#xff0c;使树中最左边的节点成为树的根节点&#xff0c;并且每个节点没有左子…

[.NET学习笔记] - Thread.Sleep与Task.Delay在生产中应用的性能测试

场景 有个Service类&#xff0c;自己在内部实现生产者/消费者模式。即多个指令输入该服务后对象后&#xff0c;Service内部有专门的消费线程执行传入的指令。每个指令的执行间隔为1秒。这里有两部分组成&#xff0c; 工作线程的载体。new Thread与Task.Run。执行等待的方法。…

大学生如何进行有效的时间管理?用待办清单APP高效管理个人时间

大学生的课外时间比较多&#xff0c;为了避免珍贵的时间被浪费&#xff0c;个人时间管理成为必不可少的技能。合理利用时间不仅能提高学习效率&#xff0c;还能充分发展自己的兴趣爱好和个人能力。那么&#xff0c;大学生如何实现有效的时间管理呢&#xff1f; 要实现有效的时…

GPT与BERT模型

NLP任务的核心逻辑是“猜概率”的游戏。BERT和GPT都是基于预训练语言模型的思想&#xff0c;通过大量语料训练得到语言模型。两种模型都是基于Transformer模型。 Bert 类似于Transformer的Encoder部分&#xff0c;GPT类似于Transformer的Decoder部分。两者最明显的在结构上的差…