java future模式 所线程实现异步调用(转载)

在多线程交互的中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.     
15.    private volatile RealData2 realData2 = null;  
16.     
19.    public boolean isFinished() {  
20.        return realData2 != null;  
21.    }  
22.      
23.     
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.     
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. import com.umpay.future.Data;
  3. public class HostServer2 {
  4. public Data request(final int count, final char c) {
  5. System.out.println("    request(" + count + ", " + c + ") BEGIN");
  6. // (1) 建立FutureData的实体
  7. final FutureData2 future2 = new FutureData2();
  8. // (2) 为了建立RealData的实体,启动新的线程
  9. new Thread() {
  10. public void run() {
  11. RealData2 realdata2 = new RealData2();
  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. return future2;
  19. }
  20. }

客户端代码:

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模式 所线程实现异步调用(转载的更多相关文章

  1. 从Java future 到 Guava ListenableFuture实现异步调用

    从Java future 到 Guava ListenableFuture实现异步调用 置顶 2016年04月24日 09:11:14 皮斯特劳沃 阅读数:17570 标签: java异步调用线程非阻 ...

  2. 从Java Future到Guava ListenableFuture实现异步调用

    原文地址: http://blog.csdn.net/pistolove/article/details/51232004 Java Future     通过Executors可以创建不同类似的线程 ...

  3. BeginInvoke 方法真的是新开一个线程进行异步调用吗?

    转自原文BeginInvoke 方法真的是新开一个线程进行异步调用吗? BeginInvoke 方法真的是新开一个线程进行异步调用吗? 参考以下代码: public delegate void tre ...

  4. java Future 模式

    考慮這樣一個情況,使用者可能快速翻頁瀏覽文件中,而圖片檔案很大,如此在瀏覽到有圖片的頁數時,就會導致圖片的載入,因而造成使用者瀏覽文件時會有停頓 的現象,所以我們希望在文件開啟之後,仍有一個背景作業持 ...

  5. java Future模式

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...

  6. java Future模式的使用

    一.Future模式的使用. Future模式简述 传统单线程环境下,调用函数是同步的,必须等待程序返回结果后,才可进行其他处理. Futrue模式下,调用方式改为异步. Futrue模式的核心在于: ...

  7. Java并发编程:线程池的使用(转载)

    文章出处:http://www.cnblogs.com/dolphin0520/p/3932921.html Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实 ...

  8. Java 里如何实现线程间通信(转载)

    出处:http://www.importnew.com/26850.html 正常情况下,每个子线程完成各自的任务就可以结束了.不过有的时候,我们希望多个线程协同工作来完成某个任务,这时就涉及到了线程 ...

  9. C# 线程池异步调用

    许多应用程序使用多个线程,但这些线程经常在休眠状态中耗费大量的时间来等待事件发生.其他线程可能进入休眠状态,并且仅定期被唤醒以轮询更改或更新状态信息,然后再次进入休眠状态.为了简化对这些线程的管理,. ...

随机推荐

  1. python基础--函数的命名空间and作用域

    函数对象:函数是第一类对象,函数名指向的值是可以被当作参数进行传递的 1.函数名可以被传递 2.函数名可以被当作参数传递给其它函数 3.函数名可以被当作函数的返回值 4.函数名可以被当作容器类型的参数 ...

  2. Linux ifconfig 配置网络接口

    Linux ifconfig 可以用来配置网络接口的IP地址.掩码.网关.物理地址等:值得一说的是用Linux ifconfig 为网卡指定IP地址,这只是用来调试网络用的,并不会更改系统关于网卡的配 ...

  3. 洛谷P1313 [NOIP2011提高组Day2T1]计算系数

    P1313 计算系数 题目描述 给定一个多项式(by+ax)^k,请求出多项式展开后x^n*y^m 项的系数. 输入输出格式 输入格式: 输入文件名为factor.in. 共一行,包含5 个整数,分别 ...

  4. js中的如何定位固定层的位置

    需要获取一些HTML的对象的坐标来更灵活的设置目标层的坐标,这里可以通过用到document.body.scrollTop等属性,但是这些属性在xhtml的标准网页中或更简单的说就是带<!DOC ...

  5. 洛谷P1063 能量项链 [2006NOIP提高组]

    P1063 能量项链 题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标 记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子 ...

  6. Leetcode3.Longest Substring Without Repeating Characters无重复字符的最长字串

    给定一个字符串,找出不含有重复字符的最长子串的长度. 示例 1: 输入: "abcabcbb" 输出: 3 解释: 无重复字符的最长子串是 "abc",其长度为 ...

  7. 【难为听】weex-ui

    eslint 不喜欢,但是确实规范了代码,同古代统一货币一样,有无穷的意义.故喜欢 weex-ui在项目中的使用方法 npm install -g weex-toolkit@latest weex c ...

  8. 人物-旅行-潘德明-Info:《近代中国徒步环游世界第一人:潘德明 》

    ylbtech-人物-旅行-潘德明-Info:<近代中国徒步环游世界第一人:潘德明 > 1.返回顶部 1. 近代中国徒步环游世界第一人:潘德明 2016-10-12 18:01 “以世界为 ...

  9. Servlet表单处理

    HttpServletRequest   继承ServletRequest  HttpServletRequest生命周期: 一个HttpServletRequest对象在用户向web服务器发送请求时 ...

  10. 可变参数与foreach 的原理

    曾经写过c++11特性使用,但是这个究竟是什么呢,和其他语言的foreach语句十分相像 函数必须具有在编译时已知的单个返回类型;当编译器可以从上下文中找出它必须是什么时,auto只会使您不必输入它. ...