在多线程交互的中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是一种高级的异步调用机制,通过使用Future对象来实现异步调用转同步。下面是一个使用Future的示例代码: ```java public class Demo3 extends BaseDemo { @Override public void callback(long response) ...
首先,异步调用的基本思想是,当一个函数或方法被调用时,它并不立即返回结果,而是立即返回一个代表未来结果的对象(如Promise或Future)。调用者可以继续执行后续任务,而不会等待该异步操作完成。当异步操作的...
这个“ICE异步调用Demo源码”是针对ICE框架的一个示例,展示了如何在C++环境中实现异步调用功能,特别是 adm 和 ami 函数的调用与异步分发。以下将详细解析这个Demo中的关键知识点: 1. **ICE框架**:ICE由ZeroC...
- 异步调用通常涉及到回调或未来(Future)对象的概念。客户端发起请求后,并不等待结果返回,而是立即继续执行其他任务,待结果准备好时,通过回调或者查询未来对象来获取结果。 - 在RMI中,可以使用Java的...
在Java中,`Future`和`ExecutorService`可以用来实现异步调用。`ExecutorService`是一个线程池服务,可以管理多个线程,而`Future`则用于获取异步任务的结果。 例如,下面是一个简单的异步调用示例: ```java ...
异步调用通常与回调函数、事件驱动和Promise(或Future)等机制相关联。例如,在JavaScript中,我们可以使用`async/await`语法来实现异步操作,使得代码更易读、更接近同步风格。在.NET框架中,异步调用主要依赖于`...
在Java编程中,异步调用是一种非常重要的技术,它允许程序在等待某个耗时操作完成的同时,继续执行其他任务,从而提高系统整体的响应性和效率。本篇将深入探讨如何在Java中实现异步调用,以及相关的核心概念和技术。...
1. **异步调用原理**:在传统的同步调用模式中,客户端发送请求后会阻塞等待服务器的响应。而异步调用则不同,客户端发送请求后不立即等待响应,而是继续执行其他任务,当服务器返回结果时,通过回调或者事件通知...
在编程领域,多线程和异步调用是提高程序性能和响应能力的重要技术。尤其在处理耗时操作,如网络请求、大数据计算或者I/O密集型任务时,多线程和异步调用能够充分利用现代多核处理器的资源,避免程序阻塞,提升用户...
总结,Java中的异步调用通过多线程、Future、Callable、CompletableFuture、回调函数等机制实现,极大地提高了程序的并发性能和响应性。在实际开发中,结合Spring框架和消息队列,我们可以构建高效、可扩展的后端...
在Spring Boot中,启用`async`异步调用是一项关键功能,它允许应用程序在处理请求时启动一个后台任务,而不必等待该任务完成。这在处理耗时操作时尤其有用,如大数据计算、发送电子邮件或文件上传等。下面将详细阐述...
在Java中,异步调用可以使用多种方式实现,例如使用Future接口、Callable接口、Runnable接口等。在本文中,我们使用了FutureTicket类来实现异步调用,FutureTicket类中包含了三个方法:makeRealData、getData和is...
在Spring Boot项目中,异步调用是一种提升应用性能的关键技术。它允许应用程序在执行一个耗时操作(如数据库查询、文件处理等)时,不阻塞主线程,从而提高系统的响应速度和并发能力。Spring Boot提供了简单易用的...
异步调用的实现方式有多种,包括使用线程池、消息队列和Future模式等。 异步调用和异步请求的区别 异步调用和异步请求都是提高服务器对客户端请求的吞吐量和响应速度的方式,但是它们的实现方式和应用场景不同。...
- **AXIS2的异步调用机制**:AXIS2使用MessageReceiver接口处理消息,对于异步调用,可以实现AsyncMessageReceiver接口。当服务端接收到请求后,不会立即返回,而是将工作交给后台线程处理,并在完成后通过回调机制...
【Spring Async:实现异步调用示例】 在软件开发中,特别是在高并发场景下,异步调用是一个重要的优化手段。同步调用是传统的执行方式,它遵循线性顺序,每个方法调用必须等待前一个方法执行完毕才能继续。而异步...
9. **取消请求**: 如果不再需要某个异步请求的结果,可以调用`Future<HttpResponse>`的`cancel()`方法来取消请求。 10. **响应处理**: 在`completed()`方法中,可以获取到`HttpResponse`对象,并从中读取状态码、头...
在Spring Boot中,异步调用是通过Spring的`@Async`注解来实现的,它允许我们在不阻塞主线程的情况下执行耗时的操作。这极大地提高了应用的响应速度,尤其是在处理大量并发请求时。接下来,我们将深入探讨如何在...
- 异步方法中的任何未捕获异常都会被记录到日志中,并且默认不会抛给调用者。若需处理这些异常,可以定义一个全局的`AsyncUncaughtExceptionHandler`。 5. **回调和通知** - Spring提供了`AsyncConfigurer`接口,...