`

Future 模式实现java 多线程异步调用

 
阅读更多

在多线程交互的中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. package  com.umpay.future;  
  2.   
  3. public   interface  Data {  
  4.     public   abstract  String getContent();  
  5. }  

 

FutureData(期权)

 

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

 

RealData(实际数据)

 

Java代码  收藏代码
  1. package  com.umpay.future.extend;  
  2.   
  3. import  java.util.Observable;  
  4.   
  5. import  com.umpay.future.Data;  
  6.   
  7. public   class  RealData2  extends  Observable  implements  Data {  
  8.   
  9.     private  String content;  
  10.   
  11.     public  RealData2() {  
  12.           
  13.     }  
  14.       
  15.     public   void  createRealData2( int  count,  char  c) {  
  16.         System.out.println("        making RealData("  + count +  ", "  + c  
  17.                 + ") BEGIN" );  
  18.         char [] buffer =  new   char [count];  
  19.         for  ( int  i =  0 ; i < count; i++) {  
  20.             buffer[i] = c;  
  21.             try  {  
  22.                 Thread.sleep(100 );  
  23.             } catch  (InterruptedException e) {  
  24.             }  
  25.         }  
  26.         System.out.println("        making RealData("  + count +  ", "  + c  
  27.                 + ") END" );  
  28.         this .content =  new  String(buffer);  
  29.           
  30.         //真实数据准备完毕了,通知FutureData2说数据已经准备好了.   
  31.         setChanged();//必须先设置本对象的状态发生了变化,并且通知所有的观察者   
  32.         notifyObservers("Finished" );  
  33.     }  
  34.       
  35.   
  36.     public  String getContent() {  
  37.         return  content;  
  38.     }  
  39. }  

 

 

服务端代码:

 

Java代码  收藏代码
  1. package  com.umpay.future.extend;  
  2.   
  3. import  com.umpay.future.Data;  
  4.   
  5. public   class  HostServer2 {  
  6.   
  7.     public  Data request( final   int  count,  final   char  c) {  
  8.         System.out.println("    request("  + count +  ", "  + c +  ") BEGIN" );  
  9.   
  10.         // (1) 建立FutureData的实体   
  11.         final  FutureData2 future2 =  new  FutureData2();  
  12.   
  13.         // (2) 为了建立RealData的实体,启动新的线程   
  14.         new  Thread() {  
  15.             public   void  run() {  
  16.                 RealData2 realdata2 = new  RealData2();  
  17.                 realdata2.addObserver(future2);//以便当RealData2把数据准备完毕后,通过该回调口子,通知FutureData2表示数据已经贮备好了   
  18.                 realdata2.createRealData2(count, c);  
  19.             }  
  20.         }.start();  
  21.   
  22.         System.out.println("    request("  + count +  ", "  + c +  ") END" );  
  23.   
  24.         // (3) 取回FutureData实体,作为传回值   
  25.         return  future2;  
  26.     }  
  27.   
  28. }  

 

客户端代码:

 

Java代码  收藏代码
  1. package  com.umpay.future;  
  2.   
  3. import  com.umpay.future.extend.HostServer2;  
  4.   
  5. public   class  MainClient {  
  6.     public   static   void  main(String[] args) {  
  7. //      testHostServer();   
  8.         testHostServer2();  
  9.     }  
  10.       
  11.     static   void  testHostServer() {  
  12.         System.out.println("main BEGIN" );  
  13.         HostServer hostServer = new  HostServer();  
  14.         Data data1 = hostServer.request(10 'A' );  
  15.         Data data2 = hostServer.request(20 'B' );  
  16.         Data data3 = hostServer.request(30 'C' );  
  17.   
  18.         System.out.println("main otherJob BEGIN" );  
  19. //        try {   
  20. //            Thread.sleep(2000);   
  21. //        } catch (InterruptedException e) {   
  22. //        }   
  23.         System.out.println("main otherJob END" );  
  24.   
  25.         System.out.println("data1 = "  + data1.getContent());  
  26.         System.out.println("data2 = "  + data2.getContent());  
  27.         System.out.println("data3 = "  + data3.getContent());  
  28.         System.out.println("main END" );  
  29.   
  30.     }  
  31.   
  32.     static   void  testHostServer2() {  
  33.         System.out.println("main BEGIN" );  
  34.         HostServer2 hostServer2 = new  HostServer2();  
  35.         Data data1 = hostServer2.request(10 'A' );  
  36.         Data data2 = hostServer2.request(20 'B' );  
  37.         Data data3 = hostServer2.request(30 'C' );  
  38.   
  39.         System.out.println("main otherJob BEGIN" );  
  40. //        try {   
  41. //            Thread.sleep(2000);   
  42. //        } catch (InterruptedException e) {   
  43. //        }   
  44.         System.out.println("main otherJob END" );  
  45.   
  46.         System.out.println("data1 = "  + data1.getContent());  
  47.         System.out.println("data2 = "  + data2.getContent());  
  48.         System.out.println("data3 = "  + data3.getContent());  
  49.         System.out.println("main END" );  
  50.   
  51.     }  
  52. }  

 

分享到:
评论

相关推荐

    Java多线程实现异步调用实例

    在本实例中,我们将深入探讨如何使用Java实现多线程以实现异步调用,并理解其背后的机制。 首先,多线程允许一个程序同时执行多个任务。在Java中,我们可以通过继承`Thread`类或实现`Runnable`接口来创建线程。在这...

    多线程异步调用(并参递参数)

    下面是一个使用Python的`concurrent.futures`模块实现多线程异步调用(并参递参数)的示例: ```python import concurrent.futures def long_running_task(param1, param2): # 这里是耗时操作 result = param1 +...

    java代码实现异步调用代码

    总结,Java中的异步调用通过多线程、Future、Callable、CompletableFuture、回调函数等机制实现,极大地提高了程序的并发性能和响应性。在实际开发中,结合Spring框架和消息队列,我们可以构建高效、可扩展的后端...

    Java实现异步调用

    本篇将深入探讨如何在Java中实现异步调用,以及相关的核心概念和技术。 1. **线程与并发** 异步调用的基础是线程并发执行。Java提供了多线程支持,通过`Thread`类或者`Runnable`接口可以创建并启动新线程。当一个...

    Java多线程实现异步调用的方法

    Java多线程实现异步调用是提高程序效率的关键技术之一。在Java中,通过创建新线程并让它们独立运行来实现异步调用,这样可以使得主线程不被长时间阻塞,从而提高程序的响应速度。以下将详细介绍如何在Java中实现这一...

    java实现线程的异步

    Java 实现线程异步是程序设计中的一个重要概念,它涉及到多任务并行处理和非阻塞执行。在Java中,我们可以通过多种方式来实现线程的异步操作,以提高程序的执行效率和响应速度。 一、Java Thread 类 Java Thread 类...

    Java多线程之异步Future机制的原理和实现共5页.p

    在Java中,异步Future机制是实现多线程并行处理的重要工具,它提供了对任务结果的预定义,允许在任务实际完成前进行后续操作。本文将深入探讨Java多线程中的异步Future机制,包括其原理、实现方式以及实际应用。 ...

    Java-多线程异步请求统一响应结果.docx

    ### Java-多线程异步请求统一响应结果 #### 多线程异步请求概念 在Java编程语言中,多线程异步请求是一种高级编程技术,它允许开发者通过创建多个独立运行的线程来同时处理不同的任务或请求。与同步请求相比,这种...

    异步调用流程图

    在实际项目中,可以利用各种编程语言(如JavaScript的Promise、async/await,Java的CompletableFuture,或者.NET的async/await)来实现异步调用。 异步调用对于优化性能和提升用户体验至关重要。例如,在网页加载中...

    JAVA 多线程的PPT和示例

    另外,java.util.concurrent包提供了高级并发工具,如BlockingQueue,它在生产者-消费者模式中非常有用,可以实现线程间的异步通信。 Java多线程的PPT和示例会详细讲解以上这些概念,并通过实例代码展示如何在实际...

    javaHttp异步请求

    5. **NIO(非阻塞I/O)**: Java的`HttpAsyncClient`依赖于Java NIO(非阻塞I/O)来实现异步操作。NIO允许单个线程处理多个连接,显著提高了系统资源的利用率。 6. **线程池**: `HttpAsyncClient`通常会使用线程池来...

    java多线程源码,仅供参考

    同步机制是Java多线程中解决竞态条件的关键,主要包含`synchronized`关键字、`Lock`接口及其实现类、`wait()`和`notify()`等方法。`synchronized`可以保证同一时刻只有一个线程访问特定的代码块,防止数据的不一致。...

    Java 模拟线程并发

    最后,Java并发库还包含了很多其他有用的工具,如Semaphore(信号量)用于控制同时访问特定资源的线程数量,CyclicBarrier(循环屏障)和CountDownLatch(计数器门锁)用于多线程间的协作,以及Lock接口及其实现如...

    Java多线程的经典资料.rar

    Java多线程是Java编程中的核心概念,它允许程序同时执行多个任务,极大地提升了软件的效率和并发性。这份“Java多线程的经典资料.rar”压缩包包含了一份名为“Java线程.pdf”的文档,很可能是关于Java多线程的详细...

    java多线程源码-source

    在Java中,实现多线程主要有两种方式:继承Thread类和实现Runnable接口。接下来,我们将深入探讨这两个方法以及相关的知识点。 1. 继承Thread类 当一个类继承了Thread类,它就自动成为一个线程类。你需要重写...

    史上最全 Java 多线程面试题及答案

    - **start()**:调用start()会启动一个新的线程,执行run()方法中的代码,实现多线程并发执行。 - **run()**:直接调用run()方法,代码将在线程调用该方法的上下文中执行,即同步执行,不产生新的线程。 4. **...

    java 多线程

    Java中可以通过以下三种方式实现多线程: 1. **继承Thread类**:通过继承`Thread`类来创建自定义线程类,并重写`run()`方法,在其中编写线程执行的代码。 2. **实现Runnable接口**:实现`Runnable`接口的`run()`...

    Java多线程编程核心技术.zip

    在Java中,实现多线程主要有两种方式:继承Thread类和实现Runnable接口。本资料"Java多线程编程核心技术.zip"深入探讨了这些核心技术,并提供了源码供学习者实践和理解。 1. **线程的创建与启动** - 继承Thread类...

    java基础多线程练习题(1)

    3. `java.util.concurrent`包:提供了更高级的并发工具,如`BlockingQueue`用于线程间的生产者-消费者模式,`ExecutorService`用于线程池管理,以及`Future`和`Callable`接口用于异步计算。 在进行多线程编程时,...

Global site tag (gtag.js) - Google Analytics