并发编程 | Future是如何优化程序性能

news2024/11/16 5:37:49

在初识Future一文中介绍了Future的核心方法。本文中接着介绍如何用Future优化我们的程序性能。 在此之前,有必要介绍Future接口的一个实现类FutureTask。

FutureTask介绍

FutureTask继承结构

首先我们看一下FutureTask的继承结构:

public class FutureTask<V> implements RunnableFuture<V>{
 ...
}

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

可以看出,FutureTask实现了RunnableFuture接口,而RunnableFuture继承了Runnable和Future,也就是说FutureTask既是Runnable,也是Future。所以 FutureTask 既可以作为 Runnable 被线程执行,又可以作为 Future 得到 Callable 的返回值。

下面的例子展示了FutureTask的 简单 用法 :

class FutureTaskCallable implements Callable{
    @Override
    public String call() throws Exception {
        return "Hello FutureTask";
    }
}

public class FutureTaskExample1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> futureTask =
                new FutureTask<>(new FutureTaskCallable());

        Thread thread = new Thread(futureTask);
        thread.start();

        System.out.println("子线程返回值:" + futureTask.get());
    }
}

//输出
子线程返回值:Hello FutureTask

这段程序中,可以看出FutureTask类的构造函数是Callable类型;在创建了FutureTask对象后,然后将这个对象当作一个 Runnable 放到 new Thread() 中去执行,最后再用 FutureTask 的 get 得到子线程 的 返回结果。简单介绍完FutureTask,现在可以进入文章的主题了:如何利用Future优化我们的程序性能。

利用Future优化程序

考虑这样一个场景,小码哥突然心血来潮想练练字了,但是他现在手头连一只钢笔都没有,书桌也是乱糟糟的,于是他打算在网购一支钢笔,然后整理书桌,就开始练字,用代码实现这个场景

普通多线程版本

我们先来看普通的多线程版本是如何实现。

//购买钢笔任务
class BuyPenRunnable implements Runnable{
    private String pen;

    @Override
    public void run() {
        System.out.println("【购买钢笔】:下单,等待送货上门");

        //模拟送货时间
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("【购买钢笔】:快递送到");
        pen = "神笔";
    }

    public String getPen() {
        return pen;
    }
}

public class CommomThreadExample {
    public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis();

        BuyPenRunnable buyPenRunnable = new BuyPenRunnable();
        Thread buyPenThread = new Thread(buyPenRunnable);
        buyPenThread.start();



        //模拟整理书桌耗时3000ms
        System.out.println("【整理书桌】:开始整理");
        Thread.sleep(3000);
        System.out.println("【整理书桌】:整理完了");

        //保证笔送到
        buyPenThread.join();

        //所有准备好,开始练字
        write(buyPenRunnable.getPen());

        long endTime = System.currentTimeMillis();
        System.out.println("总共用时 " + (endTime - startTime) + " ms");

    }

    private static void write(String pen){
        System.out.println("【开始写字】:" + pen);
    }
}


//输出
【购买钢笔】:下单,等待送货上门
【购买钢笔】:快递送到
【整理书桌】:开始整理
【整理书桌】:整理完了
【开始写字】:神笔
总共用时 5020 ms

这里尽管将购买钢笔和整理桌子并行化了,节省了时间,但是这个版本有2个问题:

  1. 通过 Runnable 实现任务,但为了获取结果,我们需要定义共享变量 pen,并提供一个方法 getPen() 来获取这个变量。

  2. 任务的取消和状态检查不方便。

Future实现

利用FutureTask实现上面的功能,代码如下:

//购买钢笔任务
class BuyPenCallable implements Callable {

    @Override
    public String call() {
        System.out.println("【购买钢笔】:下单,等待送货上门");

        //模拟送货时间
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("【购买钢笔】:快递送到");
        return "神笔";
    }
}


public class FutureTaskExample {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        long startTime = System.currentTimeMillis();

        Callable<String> buyPenCallable = () -> {
            System.out.println("【购买钢笔】:下单,等待送货上门");

            // 模拟送货时间
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("【购买钢笔】:快递送到");
            return "神笔";
        };

        FutureTask<String> futureTask = new FutureTask<>(buyPenCallable);
        ExecutorService executor = Executors.newFixedThreadPool(1);
        executor.submit(futureTask);

        // 模拟整理书桌耗时3000ms
        System.out.println("【整理书桌】:开始整理");
        Thread.sleep(3000);
        System.out.println("【整理书桌】:整理完了");


        // 尝试取消任务,如果需要这么做
        //boolean cancelled = future.cancel(false); 
        
        // 等待获取笔的结果
        String pen = futureTask.get();

        // 所有准备好,开始练字
        write(pen);

        long endTime = System.currentTimeMillis();
        System.out.println("总共用时 " + (endTime - startTime) + " ms");

        executor.shutdown();
    }

    private static void write(String pen) {
        System.out.println("【开始写字】:" + pen);
    }
}

上面的代码中,可以看到,FutureTask实现的实现方式:

  • 获取结果更方便:通过 Callable 的 call() 方法直接返回结果,不需要显式地定义共享变量和同步机制。

  • 对线程的管理更方便:FutureTask 提供了 cancel() 方法,可以取消任务,并通过 isCancelled() 和 isDone() 方法检查任务状态。

总结

在我们的实际项目中,很多时候我们的接口需要通过rpc调用去调用其它的多个服务拿到结果聚合,如果采用同步调用的方式,假设一次远程调用的时间为 300ms,则一个 Client 同步对三个 Server 分别进行一次 RPC 调 用的总时间,需要耗费 900ms。

如果使用 Future 模式对其进行改造,将同步的 RPC 调用改为异步并发的 RPC 调用,一个 Client 异步并发对三个 Server 分别进行一次 RPC 调用,那么正常情况下,大约只需要 300ms就能拿到所有服务的数据了。Future的好处不言而喻。

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

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

相关文章

JUC阻塞队列(二):LinkedBlockingQueue

1、LinkedBlockingQueue 介绍 LinkedBlockingQueue 也是接口BlockingQueue的一个实现类&#xff0c;与 ArrrayBlockingQueue基于 数组实现不同的是&#xff0c;LinkedBlockingQueue是基于单项链表实现的&#xff0c;在LinkedBlockingQueue 内部维护了一个单向链表来存储数据&am…

探索深度学习的力量:从人工智能到计算机视觉的未来科技革命

目录 1. 引言 2. 人工智能的历史背景 3. 深度学习的崛起 3.1 深度神经网络的基本原理 4. 计算机视觉的发展现状 4.1 传统计算机视觉与深度学习的结合 5. 深度学习在计算机视觉中的应用 5.1 图像分类 5.2 目标检测 6. 深度学习引领的未来科技创新与变革 7. 结论 引言…

opencv cv.findContours 函数图像轮廓层级(记录)

opencv cv.findContours 函数详解 图像轮廓层级 图像轮廓检索方式 cv.findContours contours, hierarchy cv.findContours( image, mode, method[, contours[, hierarchy[, offset]]] ) 参数1&#xff1a;源图像 参数2&#xff1a;轮廓的检索方式&#xff0c;主要参数 参数3…

专题--自底向上的计算机网络(物理层)

目录 计算机网络概述 物理层 数据链路层 网络层 运输层 应用层 网络安全 详细见http://t.csdnimg.cn/MY5aI http://t.csdnimg.cn/8Ipa4 http://t.csdnimg.cn/uvMxS

康耐视相机与发那科机器人通过Ethernet I/P直连与程序编写

配置TCP/IP&#xff1a;按MENU—SETUP—NEXT—HOSTCOMM&#xff0c;选择TCP/IP—按ENTER或者F3[DETAIL] Port#1 IP addr&#xff1a;输入机器人IP地址&#xff0c;按ENTER后输入&#xff0c;如192.168.1.11&#xff1b;如果控制柜有2个网络端口&#xff0c;则按F3[PORT]进行切换…

科创中心“核”动力|趋动科技:AI算力界的领跑者

近日&#xff0c;趋动科技与深信服正式推出联合解决方案。联合解决方案将深信服EDS的高性能存储与趋动科技OrionX AI算力资源池化软件、以及GeminiAI训练平台有机结合&#xff0c;整合存力与算力资源的同时&#xff0c;帮助用户建好AI平台、管好AI资源、用好AI服务。 双方已完成…

监控zabbix的安装与使用

文章目录 1.zabbix的安装步骤2.zabbix的主动模式和被动模式简介及实现3.zabbix proxy主动及被动4.自定义监控&#xff0c;监控linux和连接状态&#xff0c;创建email进行基础报警5.部署zabbix agent脚本&#xff0c;适配rocky和ubuntu系统6.使用脚本&#xff0c;基于zabbix api…

yolov8旋转框+关键点检测

一、Yolov8obb_kpt -----------------------------------现已在v8官方库上更新旋转框分割算法和旋转框关键点检测算法-------------------------- ------------------------------------------- https://github.com/yzqxy/ultralytics-obb_segment---------------------------…

每天五分钟深度学习框架pytorch:自动求导机制

本文重点 深度学习框架pytorch拥有自动求导的机制,自动求导是 PyTorch 中非常重要的特性,能够让我们避免手动去计算非常复杂的导数,这能够极大地减少了我们构建模型的时间。本文学习的是第10步反向传播,学习路线参考前面一篇文章。 pytorch0.4版本 在pytorch的0.4版本中…

YOLO知识点总结:

分类&#xff1a; 即是将图像结构化为某一类别的信息&#xff0c;用事先确定好的类别(category)或实例ID来描述图片。这一任务是最简单、最基础的图像理解任务&#xff0c;也是深度学习模型最先取得突破和实现大规模应用的任务。其中&#xff0c;ImageNet是最权威的评测集&…

C语言刷题日记(附详解)(1)

一、选择判断部分 第一题&#xff1a; 如下代码是否存在风险&#xff0c;并说明原因和修改方案 #include<stdio.h> int main() {char* str "hello world";*str a;return 0; }思路提示&#xff1a;这种形式的字符串存储在什么区域呢&#xff1f;是否真的有…

【个人笔记公司项目】vue项目配置代理解决跨域问题

前后端分离模式势必会遇到跨域问题&#xff0c;比如我是10.106.46.169:8080要去请求10.114.46.108:9191。下面讲下代理详细步骤。 本文步骤基于本人的项目结构 一般项目结构已支持代理 // 部署时需要将改开关置为false window.isDev trueif (window.isDev) { // Devwindow.l…

计算机网络速成(二)

计算机网络面试&#xff08;二&#xff09;-CSDN博客 OSI七层体系架构 OSI七层模型是什么&#xff1f;每层的功能是什么&#xff1f; OSI七层模型是国际标准化组织&#xff08;ISO&#xff09;制定的一个用于计算机或通信系统间互联的标准体系&#xff0c;它从上到下分别是&am…

揭秘“商业园区综合管理平台”的无代码开发流程!

本文中的素材来自我在某国资投资集团朋友小赵的“有偿”投稿&#xff0c;要知道现在的商业园区也正在经历数字化改造&#xff0c;面对多商场、多店铺的复杂管理需求&#xff0c;各类商管集团纷纷进行线上互联网管理模式的转型。 这份素材有何不同之处呢&#xff1f;因为他们走了…

EthernetIP IO从站设备数据 转IEC61850项目案例

目录 1 案例说明 1 2 VFBOX网关工作原理 1 3 准备工作 2 4 网关采集ETHERNETIP IO数据 2 5 用IEC61850协议转发数据 4 6 网关使用多个逻辑设备和逻辑节点的方法 6 7 从设备的的EDS文件获取参数信息 8 8 案例总结 10 1 案例说明 设置网关采集EthernetIP IO设备数据把采集的数据…

成功解决:el-popconfirm组件来确认删除、修改等操作无效

我 | 在这里 ⭐ 全栈开发攻城狮、全网10W粉丝、2022博客之星后端领域Top1、专家博主。 &#x1f393;擅长 指导毕设 | 论文指导 | 系统开发 | 毕业答辩 | 系统讲解等。已指导60位同学顺利毕业 ✈️个人公众号&#xff1a;热爱技术的小郑。回复 Java全套视频教程 或 前端全套视频…

深入理解java web分层架构的高内聚低耦合

​ 在软件开发中&#xff0c;构建一个高效、可维护且可扩展的应用系统一直是开发者追求的目标。分层架构和依赖注入&#xff08;IOC&#xff09;是实现这一目标的重要策略。本文将深入探讨三层架构的高内聚特性、低耦合的设计原则&#xff0c;以及如何通过IOC&#xff08;控制反…

前端宝典之五:React源码解析之深度剖析Diff算法

本文主要针对React源码进行解析&#xff0c;内容有&#xff1a; 1、Diff算法原理、两次遍历 2、Diff瓶颈及限制 3、Diff更新之单节点和多节点原理 一、Diff源码解析 以下是关于 React Diff 算法的详细解析及实例&#xff1a; 1、React Diff 算法的基本概念和重要性 1.1 概念…

非专业人员该学什么程序语言

编程&#xff0c;一度被认为和驾驶一样是一项现代社会的基本技能&#xff0c;非专业人员也该有所掌握&#xff0c;中小学也在教。但实际上&#xff0c;它的普及程度远比驾驶差&#xff0c;掌握这个技能的人很少&#xff0c;在学校学过的知识&#xff0c;因为工作中用不上也都忘…

一文弄懂评分卡是什么

在最开始的信用审批过程中,客户的信用等级主要由专家进行主观评判。随着数据分析工具的发展和数据收集、存储越来越容易,各大机构逐渐使用统计模型将专家的评判标准量化为评分卡模型。从而更有利于客观评价客户风险,和批量高效对客户进行风险分级。随着技术的发展,机器学习…