Future 模式(异步调用)

本文介绍了如何使用Future异步模式解决多线程交互中的问题,通过构建虚拟代理模式(FutureData)和回调机制,使得在生成大量数据时能保持良好的用户体验。具体包括创建FutureData对象作为承诺,启动并发线程生成真实数据(RealData),并通过观察者模式实现数据准备完毕后的通知机制,以及阻塞等待机制确保数据生成完成后再返回结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在多线程交互的中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(公共数据接口)

Java代码 收藏代码
  1. packagecom.umpay.future;
  2. publicinterfaceData{
  3. publicabstractStringgetContent();
  4. }

FutureData(期权)

Java代码 收藏代码
  1. packagecom.umpay.future.extend;
  2. importjava.util.Observable;
  3. importjava.util.Observer;
  4. importcom.umpay.future.Data;
  5. publicclassFutureData2implementsData,Observer{
  6. /**
  7. *存放真实数据,并且标志真正的数据是否已经准备完毕
  8. *被多线程享受
  9. *如果realData2==null,表示数据还准备好
  10. **/
  11. privatevolatileRealData2realData2=null;
  12. /**
  13. *查看真正的数据是否准备完毕
  14. **/
  15. publicbooleanisFinished(){
  16. returnrealData2!=null;
  17. }
  18. /**
  19. *如果数据已经准备好,则返回真正的数据;
  20. *否则,阻塞调用线程,直到数据准备完毕后,才返回真实数据;
  21. **/
  22. publicStringgetContent(){
  23. synchronized(mutex){
  24. while(!isFinished()){//只要数据没有准备完毕,就阻塞调用线程
  25. try{
  26. mutex.wait();
  27. }catch(InterruptedExceptione){
  28. e.printStackTrace();
  29. }
  30. }
  31. returnrealData2.getContent();
  32. }
  33. }
  34. /**
  35. *当RealData2准备完数据后,RealData2应该通知FutureData2数据准备完毕。
  36. *并在输入参数realData传入真实数据,在参数event传入事件(比如数据如期准备好了,或出了什么异常)
  37. *
  38. *@paramrealData真实的数据
  39. *@paramevent事件类型
  40. **/
  41. publicvoidupdate(ObservablerealData,Objectevent){
  42. System.out.println("通知...."+event);
  43. if(!(realDatainstanceofRealData2)){
  44. thrownewIllegalArgumentException("主题的数据类型必须是RealData2");
  45. }
  46. if(!(eventinstanceofString)){
  47. thrownewIllegalArgumentException("事件的数据类型必须是String");
  48. }
  49. synchronized(mutex){
  50. if(isFinished()){
  51. mutex.notifyAll();
  52. return;//如果数据已经准备好了,直接返回.
  53. }
  54. if("Finished".equals(event)){
  55. realData2=(RealData2)realData;//数据准备好了的时候,便可以通知数据准备好了
  56. mutex.notifyAll();//唤醒被阻塞的线程
  57. }
  58. }
  59. }
  60. privateObjectmutex=newObject();
  61. }

RealData(实际数据)

Java代码 收藏代码
  1. packagecom.umpay.future.extend;
  2. importjava.util.Observable;
  3. importcom.umpay.future.Data;
  4. publicclassRealData2extendsObservableimplementsData{
  5. privateStringcontent;
  6. publicRealData2(){
  7. }
  8. publicvoidcreateRealData2(intcount,charc){
  9. System.out.println("makingRealData("+count+","+c
  10. +")BEGIN");
  11. char[]buffer=newchar[count];
  12. for(inti=0;i<count;i++){
  13. buffer[i]=c;
  14. try{
  15. Thread.sleep(100);
  16. }catch(InterruptedExceptione){
  17. }
  18. }
  19. System.out.println("makingRealData("+count+","+c
  20. +")END");
  21. this.content=newString(buffer);
  22. //真实数据准备完毕了,通知FutureData2说数据已经准备好了.
  23. setChanged();//必须先设置本对象的状态发生了变化,并且通知所有的观察者
  24. notifyObservers("Finished");
  25. }
  26. publicStringgetContent(){
  27. returncontent;
  28. }
  29. }

服务端代码:

Java代码 收藏代码
  1. packagecom.umpay.future.extend;
  2. importcom.umpay.future.Data;
  3. publicclassHostServer2{
  4. publicDatarequest(finalintcount,finalcharc){
  5. System.out.println("request("+count+","+c+")BEGIN");
  6. //(1)建立FutureData的实体
  7. finalFutureData2future2=newFutureData2();
  8. //(2)为了建立RealData的实体,启动新的线程
  9. newThread(){
  10. publicvoidrun(){
  11. RealData2realdata2=newRealData2();
  12. realdata2.addObserver(future2);//以便当RealData2把数据准备完毕后,通过该回调口子,通知FutureData2表示数据已经贮备好了
  13. realdata2.createRealData2(count,c);
  14. }
  15. }.start();
  16. System.out.println("request("+count+","+c+")END");
  17. //(3)取回FutureData实体,作为传回值
  18. returnfuture2;
  19. }
  20. }

客户端代码:

Java代码 收藏代码
  1. packagecom.umpay.future;
  2. importcom.umpay.future.extend.HostServer2;
  3. publicclassMainClient{
  4. publicstaticvoidmain(String[]args){
  5. //testHostServer();
  6. testHostServer2();
  7. }
  8. staticvoidtestHostServer(){
  9. System.out.println("mainBEGIN");
  10. HostServerhostServer=newHostServer();
  11. Datadata1=hostServer.request(10,'A');
  12. Datadata2=hostServer.request(20,'B');
  13. Datadata3=hostServer.request(30,'C');
  14. System.out.println("mainotherJobBEGIN");
  15. //try{
  16. //Thread.sleep(2000);
  17. //}catch(InterruptedExceptione){
  18. //}
  19. System.out.println("mainotherJobEND");
  20. System.out.println("data1="+data1.getContent());
  21. System.out.println("data2="+data2.getContent());
  22. System.out.println("data3="+data3.getContent());
  23. System.out.println("mainEND");
  24. }
  25. staticvoidtestHostServer2(){
  26. System.out.println("mainBEGIN");
  27. HostServer2hostServer2=newHostServer2();
  28. Datadata1=hostServer2.request(10,'A');
  29. Datadata2=hostServer2.request(20,'B');
  30. Datadata3=hostServer2.request(30,'C');
  31. System.out.println("mainotherJobBEGIN");
  32. //try{
  33. //Thread.sleep(2000);
  34. //}catch(InterruptedExceptione){
  35. //}
  36. System.out.println("mainotherJobEND");
  37. System.out.println("data1="+data1.getContent());
  38. System.out.println("data2="+data2.getContent());
  39. System.out.println("data3="+data3.getContent());
  40. System.out.println("mainEND");
  41. }
  42. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值