《Java高并发程序设计》学习 --5.5 并行模式之 Future模式

2024-02-16 15:18

本文主要是介绍《Java高并发程序设计》学习 --5.5 并行模式之 Future模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

它的核心是异步调用,如果我们不着急要结果,可以让被调用者立刻返回,随后让它在后台慢慢处理这个请求,对于调用者来说则可以处理其他任务,在真正需要数据的场合再去尝试获得需要的结果。


1)Future模式的主要角色
参与者作用
Main系统启动,调用Client发出请求
Client返回Data对象,立即返回FutureData,并开始ClientThread线程装配RealData
Data返回数据的接口
FutureDataFuture数据,构造很快,但是一个虚拟的数据,需要装配RealData
FutureRealData真实的数据,其构造比较慢
它的核心结构如图所示。

2)Future模式的简单实现
在这个实现中,有一个核心接口Data,这就是客户端希望获取的数据。在Future模式中,这个Data接口有两个重要的实现,分别是RealData,也就是真是数据,这就是我们最终需要获得的,有价值的信息。另外一个就是FutureData,它就是用来提取RealData的一个“订单”。因此FutureData是可以立即返回得到。
下面是Data接口:
public interface Data {public String getResult();
}
FutureData实现了一个快速返回的RealData包装。它只是一个包装,或者说是一个RealData的虚拟实现。因此,它可以很快被构造并返回。当使用RealData准备好并注入到FutureData中,才最终返回数据。
//FutureData是Future模式的关键,它实际上是真实数据RealData的代理,封装了获取RealData的等待过程
public class FutureData implements Data {RealData realData = null; //FutureData是RealData的封装boolean isReady = false;  //是否已经准备好public synchronized void setRealData(RealData realData) {if(isReady)return;this.realData = realData;isReady = true;notifyAll(); //RealData已经被注入到FutureData中了,通知getResult()方法}@Overridepublic synchronized String getResult() throws InterruptedException {if(!isReady) {wait(); //一直等到RealData注入到FutureData中}return realData.getResult(); }
}
RealData是最终需要使用的数据模型。它的构造很慢。在这里,使用sleep()函数模拟这个过程,简单地模拟一个字符串的构造。
public class RealData implements Data {protected String data;public RealData(String data) {//利用sleep方法来表示RealData构造过程是非常缓慢的try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}this.data = data;}@Overridepublic String getResult() {return data;}
}
接下来就是我们的客户端程序,Client主要实现了获取FutureData,并开启构造RealData的线程。并在接受请求后,很快的返回FutureData。注意,它不会等待将数据真的构造完毕再返回,而是立即返回FutureData,即使这个时候FutureData并没有真实数据。
public class Client {public Data request(final String string) {final FutureData futureData = new FutureData();new Thread(new Runnable() {@Overridepublic void run() {//RealData的构建很慢,所以放在单独的线程中运行RealData realData = new RealData(string);futureData.setRealData(realData);}}).start();return futureData; //先直接返回FutureData}
}
最后,就是主函数Main,它主要负责调用Client发起请求,并消费返回的数据。
public static void main(String[] args) {Client client = new Client();Data data = client.request("name");System.out.println("请求完毕");try {Thread.sleep(2000);} catch (InterruptedException e) {		}System.out.println("数据 = " + data.getResult());
}
3)JDK中的Future模式
Future模式的基本结构,其中Future接口就类似于订单或者说是契约。通过它,可以得到真实的数据。RunnableFuture继承了Future和Runnable两个接口,其中run()方法用于构造真实的数据。它有一个具体的实现FutureTask类。FutureTask有一个内部的Sync,一些实质性工作,会委托Sync类实现。而Sync类最终会调用Callable接口,完成实际数据的组装工作。
Callable()接口只有一个方法call(),它会返回需要构造的实际数据。这个Callable接口也是这个Future框架和应用程序之间的重要接口。如果我们要实现自己的业务系统,通常需要实现自己的Callable对象。此外,FutureTask类也与应用程序密切相关,通常,我们会使用Callable实例构造一个FutureTask实例,并将它提交给线程池。
下面将展示内置的Future模式的使用:
public class JRealData implements Callable<String> {private String para;public JRealData(String para) {this.para = para;}@Overridepublic String call() throws Exception {StringBuffer sb = new StringBuffer();for(int i=0; i<10; i++) {sb.append(para);try {Thread.sleep(100);} catch (InterruptedException e) {}}return sb.toString();}
}
上述代码实现了Callable接口,它的call()方法会构造我们需要的真实数据并返回。当然这个过程可以是缓慢的,这里使用Thread.sleep()模拟它:
public class FutureMain {public static void main(String[] args) throws InterruptedException, ExecutionException {FutureTask<String> future = new FutureTask<>(new JRealData("a"));ExecutorService executor = Executors.newFixedThreadPool(1);executor.submit(future);System.out.println("请求完毕");try {Thread.sleep(2000);} catch (InterruptedException e) {}System.out.println("数据 = " + future.get());}
}
上述代码就是使用Future模式的典型。第4行,构造了FutureTask对象实例,表示这个任务是有返回值的。构造FutureTask时,使用Callable接口,告诉FutureTask我们需要的数据应该如何产生。接着,第8行,将FutureTask提交给线程池。显然,作为一个简单任务的提交,这里必然是立即返回的,因此程序不会阻塞。接下来,不用关心数据是如何产生的。可以去做一些额外的事情,然后在需要的时候就可以通过Future.get()得到实际的数据。
除了基本的功能外,JDK还为Future接口提供了一些简单的控制功能:
    boolean cancel(boolean mayInterruptIfRunning);               //取消任务boolean isCancelled();                                       //是否已经取消boolean isDone();                                            //是否已经完成V get() throws InterruptedException,ExecutionException       //取得返回对象V get(long timeout, TimeUnit unit);                          //取得返回对象,可以设置超时时间



注:本篇博客内容摘自《 Java 高并发程序设计》

这篇关于《Java高并发程序设计》学习 --5.5 并行模式之 Future模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/714931

相关文章

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Spring Boot集成/输出/日志级别控制/持久化开发实践

《SpringBoot集成/输出/日志级别控制/持久化开发实践》SpringBoot默认集成Logback,支持灵活日志级别配置(INFO/DEBUG等),输出包含时间戳、级别、类名等信息,并可通过... 目录一、日志概述1.1、Spring Boot日志简介1.2、日志框架与默认配置1.3、日志的核心作用

破茧 JDBC:MyBatis 在 Spring Boot 中的轻量实践指南

《破茧JDBC:MyBatis在SpringBoot中的轻量实践指南》MyBatis是持久层框架,简化JDBC开发,通过接口+XML/注解实现数据访问,动态代理生成实现类,支持增删改查及参数... 目录一、什么是 MyBATis二、 MyBatis 入门2.1、创建项目2.2、配置数据库连接字符串2.3、入

Springboot项目启动失败提示找不到dao类的解决

《Springboot项目启动失败提示找不到dao类的解决》SpringBoot启动失败,因ProductServiceImpl未正确注入ProductDao,原因:Dao未注册为Bean,解决:在启... 目录错误描述原因解决方法总结***************************APPLICA编

深度解析Spring Security 中的 SecurityFilterChain核心功能

《深度解析SpringSecurity中的SecurityFilterChain核心功能》SecurityFilterChain通过组件化配置、类型安全路径匹配、多链协同三大特性,重构了Spri... 目录Spring Security 中的SecurityFilterChain深度解析一、Security

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

Apache Ignite 与 Spring Boot 集成详细指南

《ApacheIgnite与SpringBoot集成详细指南》ApacheIgnite官方指南详解如何通过SpringBootStarter扩展实现自动配置,支持厚/轻客户端模式,简化Ign... 目录 一、背景:为什么需要这个集成? 二、两种集成方式(对应两种客户端模型) 三、方式一:自动配置 Thick

Spring WebClient从入门到精通

《SpringWebClient从入门到精通》本文详解SpringWebClient非阻塞响应式特性及优势,涵盖核心API、实战应用与性能优化,对比RestTemplate,为微服务通信提供高效解决... 目录一、WebClient 概述1.1 为什么选择 WebClient?1.2 WebClient 与

Java.lang.InterruptedException被中止异常的原因及解决方案

《Java.lang.InterruptedException被中止异常的原因及解决方案》Java.lang.InterruptedException是线程被中断时抛出的异常,用于协作停止执行,常见于... 目录报错问题报错原因解决方法Java.lang.InterruptedException 是 Jav