【JUC】十一、Future接口与其实现类FutureTask的优缺点

news2024/12/25 13:23:27

文章目录

  • 1、Future接口
  • 2、FutureTask结合线程池提升性能
  • 3、Future的缺点一:get导致阻塞
  • 4、Future的缺点二:轮询耗费CPU
  • 5、其余场景

相关文章: 【Callable与FutureTask】

1、Future接口

Future接口,定义了操作异步任务执行的一些方法,如获取异步任务的执行结果、取消异步任务的执行、判断任务是否被取消、判断任务是否执行完毕等,其最常用的实现类就是FutureTask,以下整理的Future的优缺点,也即FutureTask这个实现类的优缺点。

在这里插入图片描述

当主线程需要执行一个很耗时的子任务时,可通过Future把这个任务放到异步线程去执行,主线程接着做它的事或者先行结束,等过一会儿再去获取子任务执行的结果即可,这就是Future接口做的事。关键点:

  • 异步线程执行任务
  • 有返回

2、FutureTask结合线程池提升性能

比如有三个任务,用一个线程来同步执行,那就挨个来:

public class FutureTaskDemo {

    public static void main(String[] args) throws InterruptedException {
    
        long startTime = System.currentTimeMillis();
        //任务1,用sleep模拟耗时
        TimeUnit.MILLISECONDS.sleep(500);
        //任务2
        TimeUnit.MILLISECONDS.sleep(300);
        //任务3
        TimeUnit.MILLISECONDS.sleep(300);
        long endTime = System.currentTimeMillis();
        System.out.println("耗时:" + (endTime-startTime) + "ms");

    }
}

在这里插入图片描述
将任务放到异步线程去执行

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

        FutureTask<String> task1 = new FutureTask<>(() -> {
            TimeUnit.MILLISECONDS.sleep(500);
            return "task1 over";
        });
        Thread t1 = new Thread(task1, "t1");
        t1.start();
        //重复再new两个线程,传入两个FutureTask
        //...
    }

改进下,不要频繁创建和销毁线程,使用线程池

public class FutureTaskDemo {

    public static void main(String[] args) throws InterruptedException {
    
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        
        long startTime = System.currentTimeMillis();
        FutureTask<String> task1 = new FutureTask<>(() -> {
            TimeUnit.MILLISECONDS.sleep(500);
            return "task1 over";
        });
        //提交task1到线程池
        threadPool.submit(task1);
        FutureTask<String> task2 = new FutureTask<>(() -> {
            TimeUnit.MILLISECONDS.sleep(300);
            return "task2 over";
        });
        //提交task2到线程池
        threadPool.submit(task2);
        //任务3由main线程来
        TimeUnit.MILLISECONDS.sleep(300);
        long endTime = System.currentTimeMillis();
        System.out.println("耗时:" + (endTime-startTime) + "ms");
        threadPool.shutdown();
    }


}

异步显然效率更高,但这不是重点

在这里插入图片描述

以上只是异步执行任务,并没有获取异步线程上任务的执行结果,统计结束时间前,再加入get:

...
//获取下执行结果
System.out.println(task1.get());
System.out.println(task2.get());
long endTime = System.currentTimeMillis();
System.out.println("耗时:" + (endTime-startTime) + "ms");
//...

在这里插入图片描述

3、Future的缺点一:get导致阻塞

试下get的阻塞情况:

public class FutureTask2 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        FutureTask<String> futureTask = new FutureTask<String>(() ->{
            System.out.println(Thread.currentThread().getName() + "start execute task");
            TimeUnit.SECONDS.sleep(5);
            return "task over";
        });
        
        new Thread(futureTask,"t1").start();
        
        System.out.println(Thread.currentThread().getName() + "接着去忙其他的事了");
        
        System.out.println(Thread.currentThread().getName() + "忙完了,准备获取futureTask的计算结果并处理,获取中...");
        
        System.out.println(futureTask.get());
        
        System.out.println(Thread.currentThread().getName() + "结算结果获取成功,全流程结束!");

    }
}

在这里插入图片描述

  • get方法一旦调用,讲究不见不散,非要等到结果才会离开,不管FutureTask是否计算完成,因此容易导致阻塞。
  • 如果不想一直等,而是过时不候,那就get(3,TimeUnit.SECOND)
public class FutureTask2 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        FutureTask<String> futureTask = new FutureTask<String>(() ->{
            System.out.println(Thread.currentThread().getName() + "start execute task");
            TimeUnit.SECONDS.sleep(5);
            return "task over";
        });
        new Thread(futureTask,"t1").start();
        System.out.println(Thread.currentThread().getName() + "接着去忙其他的事了");
        System.out.println(Thread.currentThread().getName() + "忙完了,准备获取futureTask的计算结果并处理,获取中...");
        
        try {
            System.out.println(futureTask.get(3,TimeUnit.SECONDS));
        } catch (TimeoutException e) {
            e.printStackTrace();
            System.out.println("等待futureTask已到三秒,main过时不候了");
        }
        
        System.out.println(Thread.currentThread().getName() + "结算结果获取成功,全流程结束!");

    }
}

这里别再抛了,get的TimeOut异常,异常出来就是提高程序健壮性的,这里mian再抛就到JVM,程序会终止运行在这一行,选择捕捉处理,打印点信息后完继续往下走:

在这里插入图片描述

4、Future的缺点二:轮询耗费CPU

既然get容易阻塞,那就先调isDone,判断futureTask是否执行完成,完成再get,没完成就休息一会儿再调isDone看是否完成,轮询查看执行结果。

public class FutureTask2 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        FutureTask<String> futureTask = new FutureTask<String>(() -> {
            System.out.println(Thread.currentThread().getName() + "start execute task");
            TimeUnit.SECONDS.sleep(5);
            return "task over";
        });
        new Thread(futureTask, "t1").start();
        System.out.println(Thread.currentThread().getName() + "接着去忙其他的事了");
        System.out.println(Thread.currentThread().getName() + "忙完了,准备获取futureTask的计算结果并处理,获取中...");
        
        while (true) {
            if (futureTask.isDone()) {
                System.out.println(futureTask.get());
                break;
            } else {
                //没有完成时,不要频繁查,休息几秒再继续isDone+get
                TimeUnit.MILLISECONDS.sleep(500);
                System.out.println("futureTask线程正在处理中");
            }
        }
        Sy
        stem.out.println(Thread.currentThread().getName() + "结算结果获取成功,全流程结束!");

    }
}

在这里插入图片描述

但while(true)+break,不停的循环,下面的程序也没被接着执行,只是输出更加友好了,我们可以看到正在等get,而不是直接扔个异常出来。而这样的轮询代价确是容易导致CPU空转,耗费更多无谓的CPU资源

5、其余场景

除了阻塞和轮询耗费CPU两个缺点外,以下场景,用Future也不能优雅的实现:

回调

上面用while(true)+break不停的问futureTask完成没,繁琐且耗无谓的CPU资源,考虑FutureTask完成任务后,自己来告诉我,即回调通知。

多个任务相互依赖或者组合

在这里插入图片描述
再比如当多个异步线程之间有依赖关系时:想将多个异步任务的计算结果组合起来,且后一个异步任务的计算结果需要用前一个异步任务的值

计算速度最快

当Future任务集合中,某个任务最快结束时,需要返回结果,即比赛的第一名

在这里插入图片描述

使用Future之前提供的那点API就囊中羞涩,处理起来不够优雅,这时候还是让CompletableFuture以声明式的方式优雅的处理这些需求,Future(FutureTask这个实现类)能完成的,CompletableFuture都能完成。 ⇒ Future接口新的实现类CompletableFuture出现

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

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

相关文章

Ubuntu18 Opencv3.4.12 viz 3D显示安装、编译、使用、移植

Opencv3.*主模块默认包括两个3D库 calib3d用于相机校准和三维重建 &#xff0c;viz用于三维图像显示&#xff0c;其中viz是cmake选配。 参考&#xff1a; https://docs.opencv.org/3.4.12/index.html 下载linux版本的源码 sources。 查看cmake apt list --installed | grep…

Navicat 技术指引 | GaussDB 数据查看器

Navicat Premium&#xff08;16.2.8 Windows版或以上&#xff09; 已支持对GaussDB 主备版的管理和开发功能。它不仅具备轻松、便捷的可视化数据查看和编辑功能&#xff0c;还提供强大的高阶功能&#xff08;如模型、结构同步、协同合作、数据迁移等&#xff09;&#xff0c;这…

win10底部任务栏无响应?试试这些方法!

win10的任务栏是一个关键的用户界面元素&#xff0c;允许您轻松访问应用程序和系统功能。然而&#xff0c;有时您可能会遇到win10底部任务栏无响应的问题&#xff0c;这会妨碍您的工作流程。本篇文章将介绍解决win 10底部任务栏无响应的问题的三种方法&#xff0c;每种方法都会…

基于Vue+SpringBoot的校园疫情防控管理系统

项目编号&#xff1a; S 037 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S037&#xff0c;文末获取源码。} 项目编号&#xff1a;S037&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学生2.2 老师2.3 学校管理部门 三、…

nvm切换版本之后npm用不了

原因是 nvm只给你安了对应的node没给你安装对应的node版本的npm 解决办法如下 1找到你安装的node版本号 然后去官网下载对应的版本包 这个网址就是node官网的版本列表 Index of /download/release/ 2下载后解压 把根目录这俩复制到自己的nvm安装目录下 还有那个node_modul…

LED电子屏幕的5种色度处理技术

LED电子大屏幕行业在从单色到双色再到三基色&#xff08;全彩&#xff09;的发展过程中&#xff0c;展现了LED显示屏技术的不断创新和终端用户多元化需求的变化。为了提高LED显示屏的色彩还原能力&#xff0c;LED显示屏厂家不断改进色度处理技术。以下是LED电子大屏幕的五种色度…

debian 设置系统默认以命令行方式启动,关闭x windows

debian 设置系统默认以命令行方式启动,关闭x windows 2021-01-02 tech linux 设置 grub启动设置在/etc/default/grub中,打开 default grub 配置: $ sudo vim /etc/default/grub修改以下配置: 更新grub,设置多用户启动: $ sudo update-grub $ sudo systemctl set-…

C/C++ 开发SCM服务管理组件

SCM&#xff08;Service Control Manager&#xff09;服务管理器是 Windows 操作系统中的一个关键组件&#xff0c;负责管理系统服务的启动、停止和配置。服务是一种在后台运行的应用程序&#xff0c;可以在系统启动时自动启动&#xff0c;也可以由用户或其他应用程序手动启动。…

oracle的debjob挂載查詢

背景 有一個需求需要定時去執行一個produce&#xff0c;可以使用oracle的dbjob定時執行&#xff0c;相比較之前的vbs更加絲滑 --傳遞produce 開始的時間 頻率 declarea number;beginDBMS_JOB.SUBMIT(a,xx_warehouse_daliy_record_p;,to_date(202311230800,yyyymmddhh24mi),…

应用高斯高通滤波器提取图像轮廓

任务要求&#xff1a; 图为HALCON中的例图“tooth_rim”&#xff0c;请用高斯高通滤波器提取图像的轮廓。 任务分析&#xff1a; 图像的边缘对应频谱的高频部分&#xff0c;可以通过构造一个高频滤波器&#xff0c;过滤掉图像的低频部分&#xff0c;从而得到图像的边缘。HALC…

VSCode 连接远程服务器问题及解决办法

端口号不一样&#xff0c;需要在配置文件中添加Port Host 27.223.26.46HostName 27.223.*.*User userForwardAgent yesPort 14111输入密码后可以连接 在vscode界面&#xff0c;终端&#xff0c;生成公钥&私钥 ssh-keygen可以看到有id_rsa和id_rsa.pub两个文件生成&#…

2023年亚太数学建模C题数据分享+详细思路

在报名截止的前一天&#xff0c;我尝试进行了报名。到那时&#xff0c;已有11,000个队伍注册参赛。在我的了解中&#xff0c;在数模比赛中除了国赛美赛外&#xff0c;几乎没有其他竞赛的参赛队伍数量能与此相媲美。即便不考虑赛题的难度和认可度&#xff0c;亚太地区的这场竞赛…

Vue3实现粒子动态背景

官网&#xff1a; https://particles.js.org/ npm&#xff1a; https://www.npmjs.com/package/particles.vue3 安装 pnpm add particles.vue3 pnpm add tsparticles-slim 注册 main.js import { createApp } from vue import type { App } from vue import globleApp f…

选择ERP系统的关键指标

在制造业工厂中&#xff0c;选择一个合适的ERP系统能够显著提升生产效率、优化资源管理、增强决策支持。然而&#xff0c;如何从众多ERP系统中选择一个适合自己企业的系统&#xff0c;是许多负责人在面临的问题。本文将详细介绍选择ERP系统的关键指标&#xff0c;帮助制造业工厂…

测绘资质技术管理制度

技术管理制度 建立健全技术管理制度&#xff0c;明确技术设计、技术处理和技术总结等要求。其中简单、日常性的测绘项目可以制定《作业指导书》 质量检查管理制度 建立健全质量检查管理制度&#xff0c;明确过程检查、最终检查、质量评定、检查记录和检查报告等要求。 人员培训…

22LLMSecEval数据集及其在评估大模型代码安全中的应用:GPT3和Codex根据LLMSecEval的提示生成代码和代码补全,CodeQL进行安全评估【网安AIGC专题11.22】

LLMSecEval: A Dataset of Natural Language Prompts for Security Evaluations 写在最前面主要工作 课堂讨论大模型和密码方向&#xff08;没做&#xff0c;只是一个idea&#xff09; 相关研究提示集目标NL提示的建立NL提示的建立流程 数据集数据集分析 存在的问题 写在最前面…

基于 Modbus 的工业数据采集、控制(part 1)

HTTP 协议 简介 HTTP 是 Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;的缩写&#xff0c;是用于 Web Browser&#xff08;浏览器&#xff09;到 Web Server&#xff08;服务器&#xff09;进行数据交互的传输协议。HTTP 是一个基于 TCP 通信协议传输…

docker compose搭建渗透测试vulstudy靶场示例

前言 渗透测试&#xff08;Penetration test&#xff09;即网络安全工程师/安全测试工程师/渗透测试工程师通过模拟黑客&#xff0c;在合法授权范围内&#xff0c;通过信息搜集、漏洞挖掘、权限提升等行为&#xff0c;对目标对象进行安全测试&#xff08;或攻击&#xff09;&am…

docker部署paddleocr

内容仅供参考学习 欢迎朋友们V一起交流&#xff1a; zcxl7_7 环境 1. CentOS7  2. docker  3. PaddleOCR2.5.2 1.准备 1. 首先准备好需要打包的项目 2. 在该项目中创建Dockerfile文件 touch Dockerfile2. 编写Dockerfile # 从Python 3.8的官方镜像中创建(pyt…

OpenStack-train版安装之基础组件安装

基础组件安装 安装MariaDB&#xff08;数据库&#xff09;安装RabbitMQ&#xff08;消息队列&#xff09;安装Memcached&#xff08;缓存&#xff09; 安装MariaDB&#xff08;数据库&#xff09; 安装 # yum install mariadb mariadb-server python2-PyMySQL -y数据库配置 …