在多线程交互的中2,经常有一个线程需要得到另个一线程的计算结果,我们常用的是Future异步模式来加以解决。
Future顾名思意,有点像期货市场的“期权”,是“对未来的一种凭证”,例如当我们买了某个房地产开发商的期房,交钱之后,开发商会给我们一个凭证(期权),这个凭证告诉我们等明年某个时候拿这个凭证就可以拿到我们所需要的房子,但是现在房子还没建好。市场上之所以有“期货”,也正由于有这种需求,才有这种供给。
这种应用在GUI上用的比较多,在设计模式中一般称为“虚拟代理模式”。
例如:现在有个这样的需求,Client向Server提交一个Request(int count,char c),希望获取一个由count个字符c构造出来的字符串。比如发送Request(10,'K'),那么反馈字符串“KKKKKKKKKK”,但是我们假设这个生成字符串的过程很费时间。
于是,为了获取比较好的交互性,我们的Server收到请求后,先构造一个FutureData,并把这个所谓的“期权(未来凭证)”反馈给Client;于此同时,通过另一个并发线程去构造一个真正的字符串RealData,并在构造完毕后,RealData给FutureData报告一个消息,说数据(期房)已经准备好了,此时Client可以通过期权拿到期房,但是假如我们的Client比较着急,还没等房子假好的时,就想要房子,怎么办呢?这个时候我们可以阻塞Client所在的线程,让Client等待,直到最后RealData通知FutureData说房子好了,才返回。
这里的要点:
(1)Server先给Client一个“期权”,同时开一个线程去干活建房子(未来的“现房”);
(2)当“现房”RealData准备好了的时候,如何告诉FutureData说已经准备好了。(本处采用“回调过程”(借用观察者模式,来实现回调))
(3)如果客户比较着急,现房还没准备好的时候,就要取房,怎么办? 本处采用“阻塞”。
Data(公共数据接口)
package com.umpay.future;
public interface Data {
public abstract String getContent();
}
FutureData(期权)
package com.umpay.future.extend;
import java.util.Observable;
import java.util.Observer;
import com.umpay.future.Data;
public class FutureData2 implements Data,Observer {
/**
* 存放真实数据,并且标志真正的数据是否已经准备完毕
* 被多线程享受
* 如果realData2==null,表示数据还准备好
* */
private volatile RealData2 realData2 = null;
/**
* 查看真正的数据是否准备完毕
* */
public boolean isFinished() {
return realData2 != null;
}
/**
* 如果数据已经准备好,则返回真正的数据;
* 否则,阻塞调用线程,直到数据准备完毕后,才返回真实数据;
* */
public String getContent() {
synchronized (mutex) {
while(!isFinished()) {//只要数据没有准备完毕,就阻塞调用线程
try {
mutex.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return realData2.getContent();
}
}
/**
* 当 RealData2 准备完数据后,RealData2 应该通知 FutureData2 数据准备完毕。
* 并在输入参数 realData 传入真实数据,在参数 event 传入事件(比如数据如期准备好了,或出了什么异常)
*
* @param realData 真实的数据
* @param event 事件类型
* */
public void update(Observable realData, Object event) {
System.out.println("通知...."+event);
if(!(realData instanceof RealData2)) {
throw new IllegalArgumentException("主题的数据类型必须是RealData2");
}
if(!(event instanceof String)) {
throw new IllegalArgumentException("事件的数据类型必须是String");
}
synchronized (mutex) {
if(isFinished()) {
mutex.notifyAll();
return;//如果数据已经准备好了,直接返回.
}
if("Finished".equals(event)) {
realData2 = (RealData2)realData;//数据准备好了的时候,便可以通知数据准备好了
mutex.notifyAll();//唤醒被阻塞的线程
}
}
}
private Object mutex = new Object();
}
RealData(实际数据)
package com.umpay.future.extend;
import java.util.Observable;
import com.umpay.future.Data;
public class RealData2 extends Observable implements Data {
private String content;
public RealData2() {
}
public void createRealData2(int count, char c) {
System.out.println(" making RealData(" + count + ", " + c
+ ") BEGIN");
char[] buffer = new char[count];
for (int i = 0; i < count; i++) {
buffer[i] = c;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
System.out.println(" making RealData(" + count + ", " + c
+ ") END");
this.content = new String(buffer);
//真实数据准备完毕了,通知FutureData2说数据已经准备好了.
setChanged();//必须先设置本对象的状态发生了变化,并且通知所有的观察者
notifyObservers("Finished");
}
public String getContent() {
return content;
}
}
服务端代码:
package com.umpay.future.extend;
import com.umpay.future.Data;
public class HostServer2 {
public Data request(final int count, final char c) {
System.out.println(" request(" + count + ", " + c + ") BEGIN");
// (1) 建立FutureData的实体
final FutureData2 future2 = new FutureData2();
// (2) 为了建立RealData的实体,启动新的线程
new Thread() {
public void run() {
RealData2 realdata2 = new RealData2();
realdata2.addObserver(future2);//以便当RealData2把数据准备完毕后,通过该回调口子,通知FutureData2表示数据已经贮备好了
realdata2.createRealData2(count, c);
}
}.start();
System.out.println(" request(" + count + ", " + c + ") END");
// (3) 取回FutureData实体,作为传回值
return future2;
}
}
客户端代码:
package com.umpay.future;
import com.umpay.future.extend.HostServer2;
public class MainClient {
public static void main(String[] args) {
// testHostServer();
testHostServer2();
}
static void testHostServer() {
System.out.println("main BEGIN");
HostServer hostServer = new HostServer();
Data data1 = hostServer.request(10, 'A');
Data data2 = hostServer.request(20, 'B');
Data data3 = hostServer.request(30, 'C');
System.out.println("main otherJob BEGIN");
// try {
// Thread.sleep(2000);
// } catch (InterruptedException e) {
// }
System.out.println("main otherJob END");
System.out.println("data1 = " + data1.getContent());
System.out.println("data2 = " + data2.getContent());
System.out.println("data3 = " + data3.getContent());
System.out.println("main END");
}
static void testHostServer2() {
System.out.println("main BEGIN");
HostServer2 hostServer2 = new HostServer2();
Data data1 = hostServer2.request(10, 'A');
Data data2 = hostServer2.request(20, 'B');
Data data3 = hostServer2.request(30, 'C');
System.out.println("main otherJob BEGIN");
// try {
// Thread.sleep(2000);
// } catch (InterruptedException e) {
// }
System.out.println("main otherJob END");
System.out.println("data1 = " + data1.getContent());
System.out.println("data2 = " + data2.getContent());
System.out.println("data3 = " + data3.getContent());
System.out.println("main END");
}
}
分享到:
相关推荐
Future模式核心思想是异步调用,这里具体实现代码,其思想是:网上订了一个货之后,他会立即返回下好订单给你,你可以去做其他事,不用再一直等这个货物到达,以后有时间,货物到了,你就可以拿这个订单,去取货。...
主要给大家介绍了关于Spring Boot利用@Async异步调用:使用Future及定义超时的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用spring boot具有一定的参考学习价值,需要的朋友可以参考下
它的产生背景是公司要求服务完全异步化,一个服务可能包括RPC调用请求、MemCached请求、KV存储请求以及MySQL数据库调用,目前其它三种请求的组件都有异步化的接口,但是数据库调用并没有。所以,在这个情况下,开发...
DEPRECATED -我赞成自嘲异步未来,这是在... 如果您需要在执行某些代码之前等待两个或多个异步调用完成 阅读有关如何更多信息。 例子 带有错误处理的简单返回 var Future = require ( 'async-future' ) // node.js a
介绍C++11提供的并行程序设计的任务方法。包括异步函数,future和promise,异步可调用包装器
时间到使用超时检查器包装异步调用以防止它们无限期挂起例子 var timesUp = require ( 'times-up' ) ;function asyncFunc ( callback ) { setTimeout ( function ( ) { console . log ( 'Some process in the future...
std::async异步调用函数,在某个时候以Args作为参数(可变长参数)调用Fn,无需等待Fn执行完成就可返回,返回结果是个std::future对象。Fn返回的值可通过std::future对象的get成员函数获取。一旦完成Fn的执行,共享...
这两个任务被封装成Callable对象并返回一个Future对象,用于表示异步计算的结果。 在主线程中,我们通过调用response1.get()和response2.get()方法来获取异步计算的结果。由于这两个方法都是阻塞的(即等待异步计算...
Folly是Facebook的开源C++基础库,其中的Futures库为简化异步调用代码提供了方便。
上堂课回顾1、异步调用 ---- future模式2、事件机制 --- 异步回调3、回声测试 --- 服务就绪清单4、泛化调用 -- 不通过接口类: 救急5、d
futures模块提供了一个高层次的接口,可以调用异步执行。 异步执行可以用单独的线程来执行过程中使用线程池或processpoolexecutor。两个实现相同的接口,这是由抽象执行器类定义的。
异步注解代理的方法可以有一个返回值Future,可以用isCancelled判断异步任务是否取消,isDone判断任务是否执行结束,get获取返回结果。 个人看法:我们不使用springboot异步,也可以实现异步,但这时我们自己要建立...
CompletableFuture是Java 8中引入的一种新的Future,它是一种异步编程工具,可以用于处理异步任务的结果。 CompletableFuture的特性 CompletableFuture具有非阻塞性,可以在等待结果的同时执行其他任务,而且它支持...
【Flutter】HTTP 网络操作 ( 引入 http 插件 | 测试网站 | Get 请求 | Post 请求 | 将响应结果转为 Dart 对象 | Future 异步调用 ) https://hanshuliang.blog.csdn.net/article/details/119914643 博客源码快照
基于异步支持(回叫/承诺)。 JSON Future基于一组处理JSON的出色库,但是其中一些库使用Promise或回调样式。 这个库增加了一个额外的层来统一调用这些库。 安装 npm install json-future --save 用法 const ...
Tryton SQS 异步执行 此模块可帮助您使用 Amazon SQS 和工作线程异步执行长时间运行和阻塞的任务。 快速开始 from trytond.modules.async_sqs import async_task class MyBigReport(Report): __name__ = 'report....
期货是类似于Promises的抽象,只有两个小区别: 期货是可映射的,这意味着您可以使用任何具有映射和平面图的库来操作它们,而不必保持链接“ then”调用当调用特殊的fork方法时,Future仅开始运行异步任务。...
一个简单的RPC框架 RPC(Remote Procedure Call )——远程过程调用,它是一种通过网络从远程计算机程序上...3.支持异步调用,提供future、callback的能力。 4.能够传输基本类型、自定义业务类型、异常类型(要在客户
chapter4-1-5:使用@Async实现异步调用:使用Future以及定义超时 日志管理 chapter4-2-1:默认日志的配置 chapter4-2-2:使用log4j记录日志 chapter4-2-3:对log4j进行多环境不同日志级别的控制 chapter4-2-4:使用...
为了实现这个功能,我们使用了JavaFX的`ExecutorService`和`Future`类来异步地发送消息,并使用了一个独立的线程来监听用户输入的消息。 具体来说,在`ChatApplication`类的`start()`方法中,我们首先创建了一个...