Java并发编程—java异步Future的迭代过程

news2024/11/15 11:40:33

        在我们java多线程中,我想做一件事儿,但是我又不想影响主线程的执行,很多铁子都会想到用异步任务完成,这个时候我们的主角FutureTask就登场了。

一、FutureTask介绍

        FutureTask提供了对Future的基本实现,是一个可取消的异步计算,可以调用方法去开始和取消一个计算,可以查询计算是否完成并且获取计算结果。只有当计算完成时才能获取到计算结果,一旦计算完成,计算将不能被重启或者被取消,除非调用runAndReset方法。同时他也实现了Runnable接口,因此FutureTask交由Executor执行,可以直接用线程调用执行;

FutureTask类的架构图:

二、Future和Callable接口

        先给大家介绍2个新的接口,Future可以理解成是一个规范,FutureTask是实现了它,而Callable是需要用到的参数类型

        1、Future接口定义了操作异步任务执行一些方法,如获取异步任务的执行结果、取消任务的执行、判断任务是否被取消、判断任务是否执行完毕等。

        2、Callable接口中定义了需要有返回的任务需要实现的方法。比如主线程让一个子线程去执行任务,子线程可能比较耗时,启动子线程开始执行任务后,主线程就去做其他事情了,过一会儿才去获取子任务的执行结果;

三、简单案例

        1、了解了上面的2个接口后,这里我们去做一个案例,我要创建一个异步任务然后进行异步计算,要求返回一个计算值,且主线程继续执行,不会因为子线程的业务影响到主线程;

        //1、创建一个异步任务 传递一个Callable的接口的参数,5秒后返回一个1024
        //使用的是函数式编程,这里的参数就是Callable类型的
        FutureTask<Integer> task = new FutureTask<>(() -> {
            TimeUnit.SECONDS.sleep(5);
            return 1024;
        });
        //2、创建一个线程,把异步任务丢进去
        new Thread(task, "t1").start();
        //3、主线程继续执行
        System.out.println("程序运行执行业务中...");
        //4、获取异步任务里面的返回值
        System.out.println(task.get());
        //5、结束提醒
        System.out.println("运行结束...");

        2、上面注释说到了这个参数就是Callable类型的,这个可以从FutureTask的构造方法得到,所以这也是上面为啥要先介绍一下的原因:

 public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

        3、上面的案例我们看一下效果,在控制台里面,主程序执行业务输出语句并没有因为子线程的执行而延迟;

        4、但是,发现了一个问题,“运行结束...”这一句话是在1024输出后才输出的,所以从某种意义上造成了阻塞的现象出现,这和我们说到的高并发就相违背了。在这里的解决办法,就是将子线程的值输出这句代码放到最后进行执行,能治标不治本的解决阻塞问题,代码如下:

public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        //1、创建一个异步任务
        FutureTask<Integer> task = new FutureTask<>(() -> {
            TimeUnit.SECONDS.sleep(5);
            return 1024;
        });
        //2、创建一个线程,把异步任务丢进去
        new Thread(task, "t1").start();
        //3、主线程继续执行
        System.out.println("程序运行执行业务中...");

        //5、结束提醒
        System.out.println("运行结束...");
        //4、获取异步任务里面的返回值
        System.out.println(task.get());
    }

        5、那么出现了一个新问题,我这个主程序需要异步的这个子任务执行完成后才能结束,举个例子:铁子们在工作中调用其他程序的api,是这样等他无限的执行业务,然后获取值再做自己的业务吗,比如我这里是5s,我就必须等它5s,最终因为工作没完成,或者效率低下,岂不是只有自己背着包包走人了,所以,我们想控制一下这个时间,在规定时间范围内,等他响应该怎么用呢,解决办法如下:

System.out.println(task.get());
//用下面的代码替换上面get()
System.out.println(task.get(2,TimeUnit.SECONDS));

        6、通过替换,可以发现会报错,这个是因为规定时间内,子线程没返回数据,那肯定不是咱们主线程的问题了;

综上:在这个简单的案例中,模拟了异步操作一些耗时的业务,同时不影响主业务的进行,相信很多铁子是看懂了怎么使用异步方法,但是也有一些铁子会有疑惑,在高并发中不允许有阻塞的,那么这个阻塞该怎么解决呢。。。

四、阻塞的替代:

        给大家传播一个概念,在高并发开发中,是几乎不允许阻塞出现的,如果出现了,请用轮询去代替这个问题;

        在上面的案例中,用轮询代替阻塞现象的解决办法如下:

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

        //1、创建一个异步任务
        FutureTask<Integer> task = new FutureTask<>(() -> {
            TimeUnit.SECONDS.sleep(5);
            return 1024;
        });
        //2、创建一个线程,把异步任务丢进去
        new Thread(task, "t1").start();
        //3、主线程继续执行
        System.out.println("程序运行中...");
        //获取异步任务里面的返回值
//        System.out.println(task.get());
//        System.out.println(task.get(2,TimeUnit.SECONDS));
        //轮询获取
        while (true) {
            TimeUnit.SECONDS.sleep(1);
            if (task.isDone()) {
                System.out.println(task.get());
                break;
            } else {
                System.out.println("GGG");
            }
        }
        //结束提醒
        System.out.println("运行结束...");

    }

在这个案例中,有FutureTask里面的isDone()作为轮询使用,能勉强解决一点点问题,但是,这还不是我们想要的一个效果

比如我还想完成一些复杂的任务:

1、应对异步任务的完成时间,我希望它完成了可以告诉我,也就是我们常说的回调通知

2、将2个或者多个异步计算合成一个异步计算,这几个异步计算相互独立,同时第二个又依赖于第一个的结果

3、当Future集合中某个任务最快结束时,返回结果。

......

可想而知,在这个FutureTask里面就显得吃力了,那么该用一个什么样的方式去解决Future带给大家的困扰呢,也就是对Future的一个改进,我们该如何去改进,这个问题就留到下一篇文章给大家分享了,本篇只讲初始的异步应用,想看进阶的应用请移步:

Java并发编程—CompletableFuture的介绍和使用_小魏快起床的博客-CSDN博客

六、总结:

1、分开的子任务分开执行互不干扰可以用FutureTask执行,get()方法获取子任务的值建议放到最后;

2、Future的缺点:会有阻塞的现象出现,主要是调用了get()方法;

3、对get()优化是给get()添加等待时间,例如get(2,TimeUnit.SECONDS);

4、高并发中出现了阻塞现象请用轮询解决;

5、更深的应用场景Future会比较吃力,所以会用到CompletableFuture这个类

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

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

相关文章

aws batch 在eks上配置计算环境和提交任务

文档 Getting started with Amazon Batch on Amazon EKSAmazon EKS jobsMemory and vCPU considerations for Amazon Batch on Amazon EKS batch不会管理集群&#xff0c;只是会管理节点&#xff08;自动扩缩&#xff09;并运行任务。batch在eks中单独管理自身资源&#xff0…

异常Exception

1.异常是什么&#xff1f; 程序中可能出出现的问题 2.异常体系的最上层父类是谁&#xff1f;异常分为几类 父类&#xff1a;Exception 异常分为两类&#xff1a;编译时异常、运行时异常 3.编译时异常和运行时异常的区别 编译时异常&#xff1a;除了RuntimeException和他的子类…

华为悦盒ec6108v9c使用ADB卡刷Linux(Ubuntu)

1. adb连接华为ec6108v9c&#xff1a; adb连接盒子IP: adb connect 192.168.3.4进入adb shell: adb shell在安卓后台终端输入以下命令&#xff0c;读取盒子的 reg name 管脚对应名称: cat /dev/block/mmcblk0p1 | grep -a hi3798m 2. 用Hitool工具制作对应你盒子reg名称的烧…

Python测试进阶(一)

文章目录测试框架pytestMarkskip参数化异常处理数据驱动Allure集成生成报告Fixture基操作用域yield数据共享自动应用参数化ini运行规则配置命令行参数指定/忽略执行目录配置日志插件开发常用插件分布式并发自定义插件打包发布hook小结测试框架 先了解unittest问题分析 自动化测…

SAS,Stata,HLM,R,SPSS和Mplus分层线性模型HLM分析学生受欢迎程度数据

全文链接&#xff1a;http://tecdat.cn/?p10809本文用于比较六个不同统计软件程序&#xff08;SAS&#xff0c;Stata&#xff0c;HLM&#xff0c;R&#xff0c;SPSS和Mplus&#xff09;的两级分层线性模型的过程和输出&#xff08;点击文末“阅读原文”获取完整代码数据&#…

Java项目:SSM学生会管理系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 本项目分为管理员、学生两种角色&#xff0c; 管理员角色包含以下功能&#xff1a; 管理员登陆,管理学生,管理机构,活动信息发布,部门管理,职位…

仿SpringBoot启动Dome实现

文章目录前言环境搭建依赖项目结构实现启动获取服务器自动配置启动Tomcat总结前言 填一下以前这篇博文&#xff1a;如何纯注解整合Spring SpringMVC Mybatis埋下的坑&#xff0c;我们来简单的了解一下SpringBoot它做的一些自动配置是怎么一回事&#xff0c;同时也看看SpringBo…

【人民币识别】人民币序列号识别【含GUI Matlab源码 908期】

⛄一、简介 本文描述的人民币序列号识别系统实现了从图像预处理到识别结果的过程, 而序列号识别是本文的重要内容.以序列号区域为研究对象, 主要包括图像预处理、图像分割以及序列号识别等过程。 1 图像预处理 人民币图像总体上来说灰度偏高, 灰度值基本上都大于150 (对8位25…

具有平滑正曲线边界的一般凸体的精确闭式闵可夫斯基研究(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

Minecraft 1.19.2 Forge模组开发 04.动画效果物品

我们本次实现一个具有动画效果的物品&#xff0c;本次演示的模型代码均在文末给出 效果演示效果演示效果演示 首先&#xff0c;请确保你的开发包中引入了geckolib依赖&#xff0c;相关教程请参考:Minecraft 1.19.2 Forge模组开发 03.动画生物实体 1.首先我们要使用geckolib制…

(三)操作系统的运行环境

文章目录一、操作系统的运行机制1. 时钟管理2. 中断机制3. 原语4. 系统数据结构5. 系统调用二、操作系统体系结构1. 传统的操作系统结构&#xff08;大内核&#xff09;第一代&#xff1a;无结构OS第二代&#xff1a;模块化结构OS&#xff1a;模块-接口法OS第三代&#xff1a;分…

[附源码]计算机毕业设计springboot学习帮扶网站设计与实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

坦克大战②

1. 我方坦克发射单颗子弹 当发射一颗子弹后&#xff0c;就相当于启动一个线程来控制它的位置坐标&#xff1b;Hero[我方坦克]有子弹的对象&#xff0c;当按下J时&#xff0c;就创建一个发射子弹的线程&#xff0c;通过坐标变化让子弹不停的移动&#xff0c;形成一个射击的效果&…

redis 集群搭建的三种方式

文章目录一、Redis主从二、Redis哨兵三、Redis集群一、Redis主从 二、Redis哨兵 三、Redis集群 下载redis wget http://download.redis.io/releases/redis-5.0.3.tar.gz解压redis tar zxvf redis-5.0.3.tar.gz进行重命名 mv redis-5.0.3 redis安装gcc yum install gcc进入red…

如何学习一门技术

如何学习一门技术 同样的生活&#xff0c;在你经历了一些意外和不如意之后&#xff0c;你再回过头来看&#xff0c;之前你所抱怨的生活其实是一个蛮不错的生活。 罗翔&#xff1a;每一个人都应该拥有学习的能力和权力&#xff0c;真正的知识要能走出书斋&#xff0c;去影响每…

StarkNet 性能路线图

目录 前言 区块限制&#xff1a;Validity Rollups vs L1 为什么 L1 吞吐量有限&#xff1f; 为什么相同的障碍不影响validity rollups&#xff1f; Sequencer 并行化 Cairo-VM 的新 Rust 实现 Rust 对 sequencer重新实现 Provers呢&#xff1f; Summary 参考 前言 St…

详解设计模式:迭代器模式

迭代器模式&#xff08;Iterator Pattern&#xff09;也被称为游标模式&#xff08;Cursor Pattern&#xff09;&#xff0c;是在 GoF 23 种设计模式中定义了的行为型模式。是一种最简单也最常见的设计模式。 迭代器模式 可以让用户透过特定的接口巡访容器中的每一个元素而不用…

HTML5期末大作业:美食网页主题网站设计与实现——HTML+CSS+JavaScript月饼美食食品企业网站html模板9页面

&#x1f468;‍&#x1f393;静态网站的编写主要是用HTML DIVCSS JS等来完成页面的排版设计&#x1f469;‍&#x1f393;,常用的网页设计软件有Dreamweaver、EditPlus、HBuilderX、VScode 、Webstorm、Animate等等&#xff0c;用的最多的还是DW&#xff0c;当然不同软件写出的…

[附源码]计算机毕业设计校园运动会管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Linux基本工具——vim

Linux编辑器vim什么是vimvim的三种常用模式vim的基本操作命令模式插入模式底行模式搭配vim环境sudo怎么才能让普通用户使用什么是vim vim是linux下一款功能强大&#xff0c;多模式的编辑器。 现阶段有13种模式。 这就是进入vim的方式。 vim的三种常用模式 命令模式 我们第一…