Java Future模式

devtools/2024/9/24 0:20:41/

前言

        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.ppmy.cn/devtools/11483.html

相关文章

【JavaWeb】Day50.Mybatis的XML配置文件

XML配置文件规范 使用Mybatis的注解方式&#xff0c;主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能&#xff0c;建议使用XML来配置映射语句&#xff0c;也就是将SQL语句写在XML配置文件中。 在Mybatis中使用XML映射文件方式开发&#xff0c;需要符合一定的规…

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

XiaodiSec day034 Learn Note 小迪安全学习笔记 记录得比较凌乱&#xff0c;不尽详细 day34 黑盒审计和白盒审计 与 cms 相关 .net java php 代码审计 开始 黑盒&#xff1a;找文件上传的功能 个人用户中心是否存在文件上传功能后台管理系统是否存在文件上传功能字典目录…

Mac和VScode配置fortran

最近更换了mac电脑&#xff0c;其中需要重新配置各类软件平台和运行环境&#xff0c;最近把matlab、gmt、VScode、Endnote等软件全部进行了安装和配置。但是不得不说&#xff0c;mac系统对于经常编程的人来说还是非常友好的&#xff01; 由于需要对地震位错的程序进行编译运行…

Java注解相关

Java注解相关 TableId注解RequiredArgsConstructor TableId注解 需要 import com.baomidou.mybatisplus.annotation.TableId; <!-- 各个依赖的版本号 --><properties><spring-boot.version>3.2.5</spring-boot.version><java.version>17</j…

低代码技术与仓储管理的新纪元:革命性的供应链变革

引言 在当今数字化时代&#xff0c;企业对于创新和效率的追求越发迫切。在这样的背景下&#xff0c;低代码技术应运而生&#xff0c;成为企业数字化转型的重要工具之一。低代码技术的崛起为企业提供了一种快速、灵活、成本效益高的开发方式&#xff0c;大大缩短了软件开发周期…

软件测试面试:关键问题解析

在软件开发领域&#xff0c;测试是确保软件质量的重要环节。面试是评估软件测试人员技能和经验的关键时刻。在一个软件测试面试中&#xff0c;面试官通常会问一系列问题来评估面试者的知识、技能和解决问题的能力。本文将介绍一些常见的软件测试面试问题&#xff0c;并给出一些…

SQL--DDL数据定义语言(Oracle)

文章目录 数据定义语言创建表删除表清空表修改表修改表名&#xff0c;列名修改字段属性添加字段删除字段 数据定义语言 是针对数据库对象操作的语言 数据库对象&#xff1a;表&#xff0c;约束&#xff0c;视图&#xff0c;索引&#xff0c;序列… CREATE ---创建数据库对…

D 无限的韵律源点 (STL_set ,*****)

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 Arcaea&#xff08;韵律源点&#xff09;是一款著名的音乐游戏&#xff08;以下简称 arc&#xff09;。在 arc 中&#xff0c;玩家评分 (PTT) 是 total best 和 recent best 两部分分数维护的所…