《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

相关文章

springboot健康检查监控全过程

《springboot健康检查监控全过程》文章介绍了SpringBoot如何使用Actuator和Micrometer进行健康检查和监控,通过配置和自定义健康指示器,开发者可以实时监控应用组件的状态,... 目录1. 引言重要性2. 配置Spring Boot ActuatorSpring Boot Act

使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)

《使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)》在现代软件开发中,处理JSON数据是一项非常常见的任务,无论是从API接口获取数据,还是将数据存储为JSON格式,解析... 目录1. 背景介绍1.1 jsON简介1.2 实际案例2. 准备工作2.1 环境搭建2.1.1 添加

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

java如何分布式锁实现和选型

《java如何分布式锁实现和选型》文章介绍了分布式锁的重要性以及在分布式系统中常见的问题和需求,它详细阐述了如何使用分布式锁来确保数据的一致性和系统的高可用性,文章还提供了基于数据库、Redis和Zo... 目录引言:分布式锁的重要性与分布式系统中的常见问题和需求分布式锁的重要性分布式系统中常见的问题和需求

SpringBoot基于MyBatis-Plus实现Lambda Query查询的示例代码

《SpringBoot基于MyBatis-Plus实现LambdaQuery查询的示例代码》MyBatis-Plus是MyBatis的增强工具,简化了数据库操作,并提高了开发效率,它提供了多种查询方... 目录引言基础环境配置依赖配置(Maven)application.yml 配置表结构设计demo_st

在Ubuntu上部署SpringBoot应用的操作步骤

《在Ubuntu上部署SpringBoot应用的操作步骤》随着云计算和容器化技术的普及,Linux服务器已成为部署Web应用程序的主流平台之一,Java作为一种跨平台的编程语言,具有广泛的应用场景,本... 目录一、部署准备二、安装 Java 环境1. 安装 JDK2. 验证 Java 安装三、安装 mys

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python