Java Future模式

前言

        Future模式是并发编程的一个重要的设计模式。比如有个方法需要很长的时间才能得到结果,不会让调用的程序一直等待,而是先返回给它一张“提货卡”。其实相当于消息队列,当你下了订单之后,在并发情况下,实际不是即时就完成了整个订单流程,而是通过一个消息队列告知你完成订单,实际后台还在走逻辑。

实现原理

        Future模式中的角色:Client请求者、Host、VirtualData虚拟数据、RealData真实数据、Future提货单。

        客户端main线程创建一个host对象,接着调用host的request方法,创建一个futureData即虚拟数据对象,创建一个线程,完成之后将data返回,这个data就是一个提货卡,并不是真实的返回结果,同时在这个创建的线程里面,开始执行具体的内部逻辑,创建一个realData 即真实数据对象,当执行完,把真实数据再返回客户端main线程。

FutureTask的使用

FutureTask实现了RunnableFuture接口,RunnableFuture接口同时实现了Runnable接口和Future接口,所以FutureTask同时具有Future和Runnable的功能。

1.FutureTask+Thread
public class demo1 {public static void main(String[] args) throws ExecutionException, InterruptedException {fun1();}static void fun1() throws ExecutionException, InterruptedException {Task task = new Task();FutureTask<String> future = new FutureTask<>(task);Thread thread = new Thread(future);thread.start();System.out.println(future.get());}
}
class Task implements Callable<String> {@Overridepublic String call() throws Exception {System.out.println("done");return "ok";}
}
2.Future+ExecutorService
public class demo1 {public static void main(String[] args) throws ExecutionException, InterruptedException {fun2();}static void fun2() throws ExecutionException, InterruptedException {Task task = new Task();ExecutorService es = Executors.newCachedThreadPool();//通过future获取线程池得到的结果Future<String> future = es.submit(task);String result = future.get();System.out.println(result);}
}
class Task implements Callable<String> {@Overridepublic String call() throws Exception {System.out.println("done");return "ok";}
}
3.FutureTask+ExecutorService
    static void fun3() throws ExecutionException, InterruptedException {Task task = new Task();FutureTask future = new FutureTask<>(task);ExecutorService es = Executors.newCachedThreadPool();//将FutureTask提交给线程池执行es.submit(future);String result = (String) future.get();System.out.println(result);}
}

 CompletableFuture

        CompletableFuture是jdk8的新特性。CompletableFuture实现了CompletionStage接口和Future接口,前者是对后者的一个扩展,增加了异步会点、流式处理、多个Future组合处理的能力。

supplyAsync

supplyAsync是创建带有返回值的异步任务,一种是使用默认线程ForkJoinPool.commonPool(),另一种是使用自定义的线程池。

//默认线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {return asyncSupplyStage(ASYNC_POOL, supplier);
}
//自定义线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor) {return asyncSupplyStage(screenExecutor(executor), supplier);
}

 默认线程池:

如果调用子任务的线程不使用get或者sleep等进行等待,那么可能会在子任务还没有执行完成时,线程池就被关闭了。

   static void fun3() throws ExecutionException, InterruptedException {CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName());return "result";});//等待任务执行完成cf1.get();}
//ForkJoinPool.commonPool-worker-9

自定义线程池:

static void fun4() throws ExecutionException, InterruptedException {// 自定义线程池ExecutorService executorService = Executors.newSingleThreadExecutor();CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {System.out.println("do something....");return "result";}, executorService);//关闭线程池executorService.shutdown();
}
runAsync

runAsync是创建没有返回值的异步任务。它有如下两个方法,一个是使用默认线程池(ForkJoinPool.commonPool())的方法,一个是带有自定义线程池的重载方法。

//默认线程池
public static CompletableFuture<Void> runAsync(Runnable runnable) {return asyncRunStage(ASYNC_POOL, runnable);
}
//自定义线程池
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor) {return asyncRunStage(screenExecutor(executor), runnable);
}

获取结果的方法:

// 如果完成则返回结果,否则就抛出具体的异常
public T get() throws InterruptedException, ExecutionException // 最大时间等待返回结果,否则就抛出具体异常
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException// 完成时返回结果值,否则抛出unchecked异常。为了更好地符合通用函数形式的使用,如果完成此 CompletableFuture所涉及的计算引发异常,则此方法将引发unchecked异常并将底层异常作为其原因
public T join()// 如果完成则返回结果值(或抛出任何遇到的异常),否则返回给定的 valueIfAbsent。
public T getNow(T valueIfAbsent)// 如果任务没有完成,返回的值设置为给定值
public boolean complete(T value)// 如果任务没有完成,就抛出给定异常
public boolean completeExceptionally(Throwable ex) 

异步回调处理

thenApply

thenAccep方法时子任务与父任务使用的是同一个线程或调用线程。thenApply 表示某个任务执行完成后执行的动作,即回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,带有返回值。

static void fun5() throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName()+":cf1...");return 1;});CompletableFuture<Integer> cf = cf1.thenApply((result) -> {System.out.println(Thread.currentThread().getName()+":cf2");try {Thread.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}return result + 2;}).thenApply(res -> {System.out.println(Thread.currentThread().getName()+":cf3");return res +2 ;}).thenApply(res -> {System.out.println(Thread.currentThread().getName() + ":cf4");return res + 2;});//等待任务1执行完成System.out.println("cf1结果->" + cf1.get());//等待任务2执行完成System.out.println("cf结果->" + cf.get());}
thenApplyAsync:

thenAccepAsync在子任务中可能(有时也可能也是使用父任务的线程)是另起一个线程执行任务,并且thenAccepAsync可以自定义线程池,默认的使用ForkJoinPool.commonPool()线程池,如果传入第二个参数可指定线程池,任务将在线程池中进行。

thenRun

thenRun表示某个任务执行完成后执行的动作,即回调方法,无入参,无返回值。

static void fun8() throws ExecutionException, InterruptedException {Executor executor = Executors.newFixedThreadPool(2);CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + " cf1 do something....");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return 1;});CompletableFuture<Void> cf2 = cf1.thenRunAsync(() -> {System.out.println(Thread.currentThread().getName() + " cf2 do something....");try {Thread.sleep(0);} catch (InterruptedException e) {e.printStackTrace();}},executor).thenRunAsync(() -> {System.out.println(Thread.currentThread().getName() + " cf3 do something....");},executor);//等待任务1执行完成System.out.println("cf1结果->" + cf1.get());//等待任务2执行完成System.out.println("cf2结果->" + cf2.get());}
whenComplete

whenComplete是当某个任务执行完成后执行的回调方法,会将执行结果和执行期间抛出的异常传递给回调方法,如果是正常执行则异常为null。回调方法对应的CompletableFuture的result和该任务一致,如果该任务正常执行,则get方法返回执行结果,如果是执行异常,则get方法抛出异常。

static void fun9() throws InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread().getName() + " cf1 do something....");int a = 1/0;return 1;});CompletableFuture<Integer> cf2 = cf1.whenComplete((result, e) -> {System.out.println("上个任务结果:" + result);System.out.println("上个任务抛出异常:" + e);System.out.println(Thread.currentThread().getName() + " cf2 do something....");//抛一个异常throw new IllegalArgumentException();});//等待任务2执行完成cf2.join();
}
 

 

 

 

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

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

相关文章

Linux thermal框架介绍

RK3568温控 cat /sys/class/thermal/thermal_zone0/temp cat /sys/class/thermal/thermal_zone1/temp cat /sys/class/thermal/cooling_device0/cur_state cat /sys/class/thermal/cooling_device1/cur_state cat /sys/class/thermal/cooling_device2/cur_state thermal_zone…

【LeetCode热题100】【链表】排序链表

题目链接&#xff1a;148. 排序链表 - 力扣&#xff08;LeetCode&#xff09; 要排序一个链表&#xff0c;最快的方法是用一个数组将链表节点的值存起来然后排序数组后重新构建链表 但是从面试的角度&#xff0c;我们应该在链表原地排序&#xff0c;这里使用最简单的归并排序…

信息打点--公众号服务

微信公众号 获取微信公众号的途径https://weixin.sogou.com/ 微信公众号没有第三方服务 Github监控 人员&域名&邮箱 eg&#xff1a;xxx.cn password in:file https://gitee.com/ https://github.com/ https://www.huzhan.com/ 资源搜索 in:name test 仓库标题搜索含有…

ASP.NET教务管理平台-权限及公共模块设计与开发

摘 要 随着教育改革的不断深化&#xff0c;高等院校的建设与发展对国民整体素质的提高起着越来越重要的作用&#xff0c;建立一套能够适应这些改变的行政管理方案也就显得尤为重要。对于教务处来说&#xff0c;将信息技术用于校务管理中便是迫切的要求。 教务系统中的用户…

产品规划|如何从0到1规划设计一款产品?

我们要如何从0到1规划设计一款产品?在前期工作我们需要做什么呢?下面这篇文章就是关于此的相关内容,大家一起往下看多多了解了解吧! 一、什么是产品规划? 产品规划是一种策略,它设定了产品的价值和目标,并确定实施方案以实现这些目标。它考虑了产品的整个生命周期,基于…

HCIP-Datacom-ARST必选题库_42_排错【1道题】

一、简单题 1.在遇到网络故障时&#xff0c;工程师经常使用分层故障处理法。因为所有模型都遵循相同的基本前提&#xff0c;当模型的所有低层结构工作正常时&#xff0c;它的高层结构才能正常工作。请根据分层法将下列检查项和对应的层次匹配。TCP连接是否正确建立&#xff0c…

22长安杯电子取证复现(检材一,二)

检材一 先用VC容器挂载&#xff0c;拿到完整的检材 从检材一入手&#xff0c;火眼创建案件&#xff0c;打开检材一 1.检材1的SHA256值为 计算SHA256值&#xff0c;直接用火眼计算哈希计算 9E48BB2CAE5C1D93BAF572E3646D2ECD26080B70413DC7DC4131F88289F49E34 2.分析检材1&am…

dremio支持设置

Dremio 支持提供可用于诊断目的的设置。这些设置通过 Dremio UI&#xff1a;设置>支持启用&#xff08;或禁用&#xff09; 使用 Client Tools 可以配置当用户查看数据集中的数据时&#xff0c;Dremio 项目的工具栏上显示哪些客户端应用程序按钮。用户可以通过单击相应的工具…

海外媒体广告投放 - 大舍传媒助力企业迈向新台阶,实现精准投放

一、为何选择海外媒体广告投放 随着全球化进程的不断推进&#xff0c;越来越多的企业开始将目光投向国际市场。海外媒体广告投放作为一种有效的宣传手段&#xff0c;可以帮助企业在全球范围内提高品牌知名度和影响力&#xff0c;吸引潜在客户&#xff0c;促进产品销售。 二、…

XiaodiSec day019 Learn Note 小迪安全学习笔记

XiaodiSec day019 Learn Note 小迪安全学习笔记 记录得比较凌乱&#xff0c;不尽详细 C#相关 .NET 框架&#xff0c;多用 C#开发 内容非常少&#xff0c;和通用安全漏洞差不多 未授权访问 目录结构 反编译获得源码&#xff0c;dll 反编译 web.config 目录 dll 文件类似于…

12、【装饰器模式】动态地为对象添加新功能

你好&#xff0c;我是程序员雪球。 今天我们来聊聊 23 种设计模式中&#xff0c;一种常见的结构型模式&#xff0c;装饰器模式。聊聊它的设计思想、实现原理&#xff0c;应用场景&#xff0c;以及如何使用。 装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型…

使用d3.js画一个BoxPlot

Box Plot 在画Box Plot之前&#xff0c;先来了解下Box Plot是什么&#xff1f; 箱线图&#xff08;Box Plot&#xff09;也称盒须图、盒式图或箱型图&#xff0c;是一种用于展示数据分布特征的统计图表。 它由以下几个部分组成&#xff1a; 箱子&#xff1a;表示数据的四分…

ruoyi element-ui 实现拖拉调整图片顺序

ruoyi element-ui 实现拖拉调整图片顺序 安装sortablejs https://sortablejs.com/npm 安装sortablejs npm install sortablejs --save相关options var sortable new Sortable(el, {group: "name", // or { name: "...", pull: [true, false, clone, …

甘特图:如何制定一个有效的产品运营规划?

做好一个产品的运营规划是一个复杂且系统的过程&#xff0c;涉及多个方面和阶段。以下是一些关键步骤和考虑因素&#xff0c;帮助你制定一个有效的产品运营规划&#xff1a; 1、明确产品定位和目标用户&#xff1a; 确定产品的核心功能、特点和优势&#xff0c;明确产品在市…

python自动生成SQL语句自动化

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 Python自动生成SQL语句自动化 在数据处理和管理中&#xff0c;SQL&#xff08;Structured …

跟我学C++高级篇——获取类型名称的番外小插曲

一、获取类型名称 在前面的反射中&#xff0c;可以通过一些技术手段来实现获取类型的名称。这么一个看似简单的功能&#xff0c;其实实现起来并没有想象的那么简单。在一些框架中&#xff0c;包含了类似的功能&#xff0c;而主流的编译器则支持的各有不同。这不是说这种接口有…

【华为OD机试】处理器问题

目录 题目描述 输入描述 输出描述 用例 考察算法&#xff1a;深度优先搜索 题目解析 步骤1&#xff1a;确定每个链路上可用的处理器数量 步骤2&#xff1a;确定最佳的芯片组合策略 步骤3&#xff1a;选择合适的芯片组合 算法实现 实现一 实现二 实现三 题目描述 …

统一SQL 支持Oracle CHAR和VARCHAR2 (size BYTE|CHAR)转换

统一SQL介绍 https://www.light-pg.com/docs/LTSQL/current/index.html 源和目标 源数据库&#xff1a;Oracle 目标数据库&#xff1a;Postgresql&#xff0c;TDSQL-MySQL&#xff0c;达梦8&#xff0c;LightDB-Oracle 操作目标 在Oracle中的CHAR和VARCHAR2数据类型&…

揭开ChatGPT面纱(1):准备工作(搭建开发环境运行OpenAI Demo)

文章目录 序言&#xff1a;探索人工智能的新篇章一、搭建开发环境二、编写并运行demo1.代码2.解析3.执行结果 本博客的gitlab仓库&#xff1a;地址&#xff0c;本博客对应01文件夹。 序言&#xff1a;探索人工智能的新篇章 随着人工智能技术的飞速发展&#xff0c;ChatGPT作为…

nginx服务访问页面白色

问题描述 访问一个域名服务返回页面空白&#xff0c;非响应404。报错如下图。 排查问题 域名解析正常&#xff0c;网络通讯正常&#xff0c;绕过解析地址访问源站IP地址端口访问正常&#xff0c;nginx无异常报错。 在打开文件时&#xff0c;发现无法打开配置文件&#xff0c…