Future 模式(异步调用)

http://eyesmore.iteye.com/blog/243648

在多线程交互的中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程序执行超时——Future接口介绍

http://westyi.iteye.com/blog/714935

在Java中,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现。 Future接口是Java标准API的一部分,在java.util.concurrent包中。Future接口是Java线程Future模式的实 现,可以来进行异步计算。

Future模式可以这样来描述:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时 间之后,我就便可以从Future那儿取出结果。就相当于下了一张订货单,一段时间后可以拿着提订单来提货,这期间可以干别的任何事情。其中Future 接口就是订货单,真正处理订单的是Executor类,它根据Future接口的要求来生产产品。

Future接口提供方法来检测任务是否被执行完,等待任务执行完获得结果,也可以设置任务执行的超时时间。这个设置超时的方法就是实现Java程 序执行超时的关键。

Future接口是一个泛型接口,严格的格式应该是Future<V>,其中V代表了Future执行的任务返回值的类型。 Future接口的方法介绍如下:

·         boolean cancel (boolean mayInterruptIfRunning) 取消任务的执行。参数指定是否立即中断任务执行,或者等等任务结束

·         boolean isCancelled () 任务是否已经取消,任务正常完成前将其取消,则返回 true

·         boolean isDone () 任务是否已经完成。需要注意的是如果任务正常终止、异常或取消,都将返回true

·         V get () throws InterruptedException, ExecutionException  等待任务执行结束,然后获得V类型的结果。InterruptedException 线程被中断异常, ExecutionException任务执行异常,如果任务被取消,还会抛出CancellationException

·         V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能一样,多了设置超时时间。参数timeout指定超时时间,uint指定时间的单位,在枚举类TimeUnit中有相关的定义。如果计 算超时,将抛出TimeoutException

Future的实现类有java.util.concurrent.FutureTask<V>即 javax.swing.SwingWorker<T,V>。通常使用FutureTask来处理我们的任务。FutureTask类同时又 实现了Runnable接口,所以可以直接提交给Executor执行。使用FutureTask实现超时执行的代码如下:

Java代码  

1.  ExecutorService executor = Executors.newSingleThreadExecutor();

2.  FutureTask<String> future =

3.         new FutureTask<String>(new Callable<String>() {//使用Callable接口作为构造参数

4.           public String call() {

5.             //真正的任务在这里执行,这里的返回值类型为String,可以为任意类型

6.         }});

7.  executor.execute(future);

8.  //在这里可以做别的任何事情

9.  try {

10.     result = future.get(5000, TimeUnit.MILLISECONDS); //取得结果,同时设置超时执行时间为5秒。同样可以用future.get(),不设置执行超时时间取得结果

11. } catch (InterruptedException e) {

12.     futureTask.cancel(true);

13. } catch (ExecutionException e) {

14.     futureTask.cancel(true);

15. } catch (TimeoutException e) {

16.     futureTask.cancel(true);

17. } finally {

18.     executor.shutdown();

19. }

不直接构造Future对象,也可以使用ExecutorService.submit方法来获得Future对象,submit方法即支持以 Callable接口类型,也支持Runnable接口作为参数,具有很大的灵活性。使用示例如下:

Java代码  

1.  ExecutorService executor = Executors.newSingleThreadExecutor();

2.  FutureTask<String> future = executor.submit(

3.     new Callable<String>() {//使用Callable接口作为构造参数

4.         public String call() {

5.        //真正的任务在这里执行,这里的返回值类型为String,可以为任意类型

6.     }});

7.  //在这里可以做别的任何事情

8.  //同上面取得结果的代码

利用Future接口实现程序执行超时大致用法就这么多,改天需要研究下Future接口的内部实现,特别是设定执行超时的实现。

转载于:https://www.cnblogs.com/DreamSea-for-Jimmy/archive/2011/09/06/2168572.html

Async Mode: Future使用相关推荐

  1. C++并发编程之std::async(), std::future, std::promise, std::packaged_task

    c++11中增加了线程,使得我们可以非常方便的创建线程,它的基本用法是这样的: void f(int n); std::thread t(f, n + 1); t.join(); 但是线程毕竟是属于比 ...

  2. C++async、future、packaged_task、promise的使用

    对线程又有了深刻的认识,以前写的线程基本都是同步线程,而自从学习了muduo网络库更知道要用异步的思想去处理问题,因为有时候同步是必须的,但有的时候同步会造成本不必要的浪费,所以也适当的用异步操作来代 ...

  3. C++多线程std::async、std::future、std::packaged_task、std::promise

    std::async std::async用于创建异步任务,实际上就是创建一个线程执行相应任务,默认立即开始执行. std::async就是异步编程的高级封装,std::async的操作,其实相当于封 ...

  4. std::future、std::promise、std::packaged_task、std::async

    #include <iostream> #include <string> #include <future> #include <thread> #i ...

  5. C++11中std::future的使用

    C++11中的std::future是一个模板类.std::future提供了一种用于访问异步操作结果的机制.std::future所引用的共享状态不能与任何其它异步返回的对象共享(与std::sha ...

  6. SpringBoot巧用 @Async 提升API接口并发能力!

    异步调用几乎是处理高并发Web应用性能问题的万金油,那么什么是"异步调用"? "异步调用"对应的是"同步调用",同步调用指程序按照定义顺序依 ...

  7. SpringBoot巧用 @Async 提升API接口并发能力

    异步调用几乎是处理高并发Web应用性能问题的万金油,那么什么是"异步调用"? "异步调用"对应的是"同步调用",同步调用指程序按照定义顺序依 ...

  8. @async 没有异步_spring boot使用@Async异步任务

    欢迎关注微信公众号:xiaosen_javashare github项目地址:https://github.com/lgsdaredevil/asyncTest 开启异步任务 在应用主类中添加@Ena ...

  9. How To Do @Async in Spring--转

    原文地址:http://www.baeldung.com/spring-async 1. Overview In this article, we'll explore the asynchronou ...

最新文章

  1. 安装sql 2005 闪退 连接到服务器失败。错误:0x80070424
  2. lib和dll文件的区别和联系
  3. 用python解析html[SGMLParser]
  4. mongodb学习(六)索引
  5. 什么意思呢_technician是什么意思
  6. 三角函数公式、诱导公式
  7. mysql 合并left join 数据条目
  8. BZOJ3091: 城市旅行
  9. FPGA学习之路—应用程序—原码二位乘法器及Verilog代码分析
  10. json对象转换成string的方法
  11. 鸿蒙空间是什么星辰变,飞升之后做什么《星辰变》神魔妖界收伏奇珍异兽
  12. mysql 垂直分表技术的实战演练,有实战代码。
  13. 不会日语也能在日本点菜 | 通用篇
  14. HBuilderX使用mac打包ios应用提示苹果根证书没有安装
  15. 信息安全等级测评内容
  16. [原创]WIA 学习笔记
  17. [VCS]Coverage Options Introduction
  18. 网友测试:优品拍拍二手交易平台
  19. 如何多个进程监听同一个端口
  20. 波特率、数据传输速率和带宽的关系(转)

热门文章

  1. TCP连接建立系列 — 服务端接收ACK段(二)
  2. java线程挂起唤醒_JAVA并发(10)—interrupt唤醒挂起线程
  3. leetcode算法题--用两个栈实现队列
  4. js 判断支持webgl_基于WebGL无插件虚拟场景漫游技术如何构建?ThingJS
  5. Valgrind 使用简单说明
  6. Allure Report使用
  7. idea没有错误出现红色波浪线怎么去掉?
  8. CrazyWing:Python自动化运维开发实战 四、Python变量
  9. 研究人员首次实现人脑实时连接互联网,攻壳社会的前奏?
  10. ABP理论学习之授权(Authorization)