`

Future模式

阅读更多

http://www.cnblogs.com/edwardlost/archive/2010/12/26/1917238.html

 

Future模式

在多线程交互的中,经常有一个线程需要得到另个一线程的计算结果,我们常用的是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(公共数据接口)

1
2
3
4
5
package com.umpay.future;
  
public interface Data {
    public abstract String getContent();
}

 

FutureData(期权)

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

 

RealData(实际数据)

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

 

服务端代码

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

 

客户端代码

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

 

 

参考文章:

1. Future模式(异步调用)

2. Design Pattern: Future 模式

3. 什么是java future模式

 

分享到:
评论

相关推荐

    31 凭票取餐—Future模式详解.pdf

    【31 凭票取餐—Future模式详解】 在Java并发编程中,Future模式是一种常见的设计模式,它允许主线程在不阻塞的情况下启动一个异步任务,然后在需要时获取任务的结果。Future模式的灵感来源于现实生活中的场景,如...

    future模式案例代码

    Future模式核心思想是异步调用,这里具体实现代码,其思想是:网上订了一个货之后,他会立即返回下好订单给你,你可以去做其他事,不用再一直等这个货物到达,以后有时间,货物到了,你就可以拿这个订单,去取货。...

    Spring Boot对Future模式的支持详解

    Spring Boot对Future模式的支持使得开发者可以更方便地在应用程序中实现异步处理,从而提高系统的并发性能和响应速度。在实际开发中,当遇到需要执行耗时操作或复杂计算时,我们可以利用多线程来提升效率,而Future...

    老生常谈java中的Future模式

    老生常谈java中的Future模式 在 Java 中,Future 模式是一种常用的设计模式,用于处理并发编程中的多线程问题。在这个模式中,线程 A 需要等待线程 B 的结果,但线程 A 不需要一直等待线程 B,可以先拿到一个未来的...

    asyncj:使用 Future 模式或回调(NodeJS 风格)进行异步非阻塞编程的灵活而简单的库。 没有第三方依赖,没有重量级的包装器和类,没有废话,只需添加 maven 依赖并构建可扩展的应用程序

    灵活且超轻量级的库,用于使用 Future 模式、回调(NodeJS 风格)和异步非阻塞编程。 动机 该库的第一个目标是为 Java 8 提供模式的轻量级实现。此外,该库还提供对 Java 流水线的支持。 第二个目的是演示 Java 8 ...

    nio+Future.rar

    在Java编程领域,NIO(New Input/Output)和Future模式是两个重要的概念,它们分别在并发处理和异步操作中发挥着关键作用。这里我们将深入探讨这两个知识点,并结合压缩包中的"nioStudy"文件来解析它们的应用。 一...

    Callable和Future.doc

    Java 中的 Future 模式允许我们提交一个异步任务并获取其结果,而无需直接管理线程。我们可以在提交任务后继续执行其他操作,稍后再通过 Future 对象获取结果。这种方式提高了程序的并发性和灵活性。 在实际应用中...

    简单讲解Java的Future编程模式

    Future模式的优势在于它能够将异步的数据驱动自然地融入到顺序流程中,使得并发代码保持简洁和优雅。与回调驱动相比,Future模式避免了回调函数中可能出现的线程安全问题,同时提供了更好的顺序流程控制。回调虽然...

    java多线程设计模式详解

    Future模式允许启动一个异步操作,并在后续代码中获取结果。Java的`Future`接口和`Callable`接口结合`ExecutorService`可以实现这一模式,提高程序的响应速度。 八、线程局部变量模式 线程局部变量(`ThreadLocal`)...

    JAVA设计模式

    5. **Future模式**:Future模式是一种并发设计模式,它提供了异步操作的结果。在Java中,`java.util.concurrent.Future`接口代表一个异步计算的结果,可以检查计算是否完成,取消计算,或者获取计算结果。通常与...

    并发设计模式

    - Future模式:异步执行任务并返回结果,提供了一种机制来获取异步任务的结果。 - 生产者消费者模式:管理不同线程之间的数据交换。 #### 三、单例模式详解 单例模式是一种常用的创建型设计模式,它确保一个类...

    java多线程设计模式详解.pdf

    3. 同步和通信模式:探讨在多线程程序中,线程间的同步机制和通信手段,如信号量、栅栏、Future模式等。 4. 并发集合和映射的设计模式:介绍在多线程环境中,如何安全地使用集合数据结构,以及专门针对并发访问设计...

    多线程设计模式.rar

    7. **future模式**:future模式用于异步计算的结果获取。Java的`Future`接口和`Callable`接口配合`ExecutorService`,可以预提交任务并在未来某个时刻获取结果。 8. **竞争条件(Race Condition)和死锁避免**:在...

    线程超时死掉

    Future接口是Java线程Future模式的实 现,可以来进行异步计算。 Future模式可以这样来描述:我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时 间之后,我就便...

    Java多线程设计模式.pdf

    **定义:**Future模式是一种允许客户端异步地获取结果的模式。它提供了一个代理对象(Future),该对象代表了某个正在进行的任务的结果。 **关键要素:** - `Future`接口:表示计算结果的未来可用性。 - `...

    Java并发编程的设计原则与模式

    5. **future模式**:Future接口代表异步计算的结果,可以查询计算是否完成,获取结果,甚至取消计算。CompletableFuture提供更强大的异步编程支持。 四、Java并发工具 1. **CountDownLatch**:用于计数,当计数到达...

    java多线程设计模式

    7. **Future模式**:异步编程模型中的一种设计模式,用户提交一个任务并获取一个Future对象,当任务完成时可以通过Future对象获取结果。 8. **责任链模式**:将多个处理步骤组织成一条链,每个处理步骤负责一部分...

    java多线程设计模式详解.rar

    6. **future模式**:`Future`接口和`Callable`接口一起使用,可以异步执行任务并获取结果。这在等待某个耗时操作完成,而不阻塞当前线程的情况下非常有用。 7. **线程间通信模式**:`wait()`、`notify()`和`...

    设计模式-.NET并行编程

    本书共7章:第1章主要介绍并行编程的基本概念与并行计算的基础理论,第2章主要介绍并行循环的知识,第3章介绍并行任务处理,第4章阐述并行合并计算的机理,第5章介绍future模式,第6章在前文的基础上深入探讨动态...

Global site tag (gtag.js) - Google Analytics