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. VMWare 下 Ubuntu 18.04 的文件共享

    突然某天发现 /mnt/hgfs 下共享的文件夹没了... apt-get install open-vm-tools mkdir /mnt/hgfs vmhgfs-fuse .host:/ /mnt ...

  2. 关于网上大量对Vue双向绑定的错误理解

    对于Vue的双向绑定,现在基本是个前端都听说过,面试官也喜欢问这个问题.但对于Vue双向绑定的原理,掘金.博客园和segmentfault等技术社区充斥着大量的错误文章.这些文章的题目基本样子如下 “ ...

  3. Scanner读取记事本文件内容为空的解决办法

    原因:记事本txt文件中含有中文,windows记事本编码方式为gbk,但是eclipse中为utf-8,所以需要在Scanner中指定编码方式.

  4. [DEPRECATION] Encountered positional parameter near xxx Positional parameter are considered deprecated; use named parameters or JPA-style positional parameters instead.

    WARN:30 20:55:45,340ms- [HqlSqlWalker]1009行-[DEPRECATION] Encountered positional parameter near line ...

  5. Eclipse-搭建springboot项目报错

    Eclipse Maven pom报错: org.apache.maven.archiver.MavenArchiver.getManifest(org.apache.maven.project.Ma ...

  6. 大数据概念(4V)

  7. BZOJ1452 [JSOI2009]Count [2017年4月计划 树状数组02]

    1452: [JSOI2009]Count Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 2419  Solved: 1403[Submit][Stat ...

  8. for循环取出每个i的值

    <!DOCTYPE html> <html> <head> <title></title> </head> <body&g ...

  9. 有趣的HTML5 Web 存储

    HTML5 web 存储,一个比cookie更好的本地存储方式. 什么是 HTML5 Web 存储? 使用HTML5可以在本地存储用户的浏览数据. 早些时候,本地存储使用的是 cookie.但是Web ...

  10. .net core/.net 使用 CommandLineParser 来标准化地解析命令行

    CommandLineParser 是一款用于解析命令行参数的 NuGet 包.你只需要关注你的业务,而命令行解析只需要极少量的配置代码. 本文将介绍如何使用 CommandLineParser 高效 ...