Java多线程编程中Future模式的详解<转>

Java多线程编程中,常用的多线程设计模式包括:Future模式、Master-Worker模式、Guarded Suspeionsion模式、不变模式和生产者-消费者模式等。这篇文章主要讲述Future模式,关于其他多线程设计模式的地址如下:
关于其他多线程设计模式的地址如下:
关于Master-Worker模式的详解: Java多线程编程中Master-Worker模式的详解
关于Guarded Suspeionsion模式的详解: Java多线程编程中Guarded Suspeionsion模式的详解
关于不变模式的详解: Java多线程编程中不变模式的详解
关于生产者-消费者模式的详解:生产者-消费者模式Java详解

1. Future模式核心思想

Future模式的核心在于:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑(根据《Java程序性能优化》)。

Future模式有点类似于商品订单。在网上购物时,提交订单后,在收货的这段时间里无需一直在家里等候,可以先干别的事情。类推到程序设计中时,当提交请求时,期望得到答复时,如果这个答复可能很慢。传统的时一直等待到这个答复收到时再去做别的事情,但如果利用Future设计模式就无需等待答复的到来,在等待答复的过程中可以干其他事情。

例如如下的请求调用过程时序图。当call请求发出时,需要很长的时间才能返回。左边的图需要一直等待,等返回数据后才能继续其他操作;而右边的Future模式的图中客户端则无需等到可以做其他的事情。服务器段接收到请求后立即返回结果给客户端,这个结果并不是真实的结果(是虚拟的结果),也就是先获得一个假数据,然后执行其他操作。

2. Future模式Java实现

Client的实现

Client主要完成的功能包括:1. 返回一个FutureData;2.开启一个线程用于构造RealData。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

public class Client {

    public Data request(final String string) {

        final FutureData futureData = new FutureData();

        

        new Thread(new Runnable() {

            @Override

            public void run() {

                //RealData的构建很慢,所以放在单独的线程中运行

                RealData realData = new RealData(string);

                futureData.setRealData(realData);

            }

        }).start();

        

        return futureData; //先直接返回FutureData

    }

}

Data的实现

无论是FutureData还是RealData都实现该接口。

?


1

2

3

public interface Data {

    String getResult() throws InterruptedException;

}

FutureData的实现

FutureData是Future模式的关键,它实际上是真实数据RealData的代理,封装了获取RealData的等待过程。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

//FutureData是Future模式的关键,它实际上是真实数据RealData的代理,封装了获取RealData的等待过程

public class FutureData implements Data {

    RealData realData = null; //FutureData是RealData的封装

    boolean isReady = false//是否已经准备好

    

    public synchronized void setRealData(RealData realData) {

        if(isReady)

            return;

        this.realData = realData;

        isReady = true;

        notifyAll(); //RealData已经被注入到FutureData中了,通知getResult()方法

    }

    @Override

    public synchronized String getResult() throws InterruptedException {

        if(!isReady) {

            wait(); //一直等到RealData注入到FutureData中

        }

        return realData.getResult();

    }

}

RealData的实现

RealData是最终需要使用的数据,它的构造函数很慢。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public class RealData implements Data {

    protected String data;

    public RealData(String data) {

        //利用sleep方法来表示RealData构造过程是非常缓慢的

        try {

            Thread.sleep(1000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        this.data = data;

    }

    @Override

    public String getResult() {

        return data;

    }

}

测试运行

主函数主要负责调用Client发起请求,并使用返回的数据。

?


1

2

3

4

5

6

7

8

9

10

11

12

public class Application {

    public static void main(String[] args) throws InterruptedException {

        Client client = new Client();

        //这里会立即返回,因为获取的是FutureData,而非RealData

        Data data = client.request("name");

        //这里可以用一个sleep代替对其他业务逻辑的处理

        //在处理这些业务逻辑过程中,RealData也正在创建,从而充分了利用等待时间

        Thread.sleep(2000);

        //使用真实数据

        System.out.println("数据="+data.getResult());

    }

}

3. Future模式的JDK内置实现

由于Future是非常常用的多线程设计模式,因此在JDK中内置了Future模式的实现。这些类在java.util.concurrent包里面。其中最为重要的是FutureTask类,它实现了Runnable接口,作为单独的线程运行。在其run()方法中,通过Sync内部类调用Callable接口,并维护Callable接口的返回对象。当使用FutureTask.get()方法时,将返回Callable接口的返回对象。同样,针对上述的实例,如果使用JDK自带的实现,则需要作如下调整。

首先,Data接口和FutureData就不需要了,JDK帮我们实现了。

其次,RealData改为这样:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

import java.util.concurrent.Callable;

public class RealData implements Callable<string> {

    protected String data;

    public RealData(String data) {

        this.data = data;

    }

    @Override

    public String call() throws Exception {

        //利用sleep方法来表示真是业务是非常缓慢的

        try {

            Thread.sleep(1000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        return data;

    }

}</string>

最后,在测试运行时,这样调用:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.FutureTask;

public class Application {

    public static void main(String[] args) throws Exception {

        FutureTask<string> futureTask =

                new FutureTask<string>(new RealData("name"));

        ExecutorService executor =

                Executors.newFixedThreadPool(1); //使用线程池

        //执行FutureTask,相当于上例中的client.request("name")发送请求

        executor.submit(futureTask);

        //这里可以用一个sleep代替对其他业务逻辑的处理

        //在处理这些业务逻辑过程中,RealData也正在创建,从而充分了利用等待时间

        Thread.sleep(2000);

        //使用真实数据

        //如果call()没有执行完成依然会等待

        System.out.println("数据=" + futureTask.get());

    }

}</string></string>

本文完。转载请注明出处。

转自  http://www.2cto.com/kf/201411/351903.html

时间: 2024-08-02 07:00:26

Java多线程编程中Future模式的详解<转>的相关文章

Java多线程编程中的lock使用源码详解

将做工程过程重要的代码段做个记录,如下的代码内容是关于Java多线程编程中的lock使用详解的代码,应该是对码农有帮助. import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.locks.Lock; import java.util.concurrent.l

java多线程编程中实现Runnable接口方法相对于继承Thread方法的优势

 java多线程创建方法http://blog.csdn.net/cjc211322/article/details/24999163  java创建多线程方法之间的区别http://blog.csdn.net/cjc211322/article/details/25000449 java多线程编程中实现Runnable接口方法相对于继承Thread方法的优势

Java 多线程(六) synchronized关键字详解

Java 多线程(六) synchronized关键字详解 多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题. 同步机制可以使用synchronized关键字实现. 当synchronized关键字修饰一个方法的时候,该方法叫做同步方法. 当synchronized方法执行完或发生异常时,会自动释放锁. 下面通过一个例子来对synchronized关键字的用法进行解析. 1.是否使用synchronized关键字的不同 例子

C#函数式编程中的部分应用详解

何谓函数式编程 相信大家在实际的开发中,很多情况下完成一个功能都需要借助多个类,那么我们这里的基本单元就是类.而函数式编程则更加细化,致使我们解决一个功能的基本单元是函数,而不是类,每个功能都是由多个函数构成,并且函数之间没有直接的关系.如果简单的文字描述还不足以让你理解,下面我们就配以图来演示. 如下图所示,图左是我们设计好的三个函数,而右边则是我们需要实现的功能.而我们需要做的就是利用这三个函数去完成对应的三个功能,笔者在这里只是进行简单而又形象的表述,实际的开发过程可能需要更多的函数,并且

java并发编程(七)synchronized详解

Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码.     一.当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行.另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块.      二.然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(thi

Java设计模式之享元模式实例详解

本文实例讲述了Java设计模式之享元模式.分享给大家供大家参考,具体如下: 解释一下概念:也就是说在一个系统中如果有多个相同的对象,那么只共享一份就可以了,不必每个都去实例化一个对象.比如说一个文本系统,每个字母定一个对象,那么大小写字母一共就是52个,那么就要定义52个对象.如果有一个1M的文本,那么字母是何其的多,如果每个字母都定义一个对象那么内存早就爆了.那么如果要是每个字母都共享一个对象,那么就大大节约了资源. 在Flyweight模式中,由于要产生各种各样的对象,所以在Flyweigh

java多线程同步以及线程间通信详解&amp;消费者生产者模式&amp;死锁&amp;Thread.join()(多线程编程之二)

本篇我们将讨论以下知识点: 1.线程同步问题的产生 什么是线程同步问题,我们先来看一段卖票系统的代码,然后再分析这个问题: [java] view plain copy print? package com.zejian.test; /** * @author zejian * @time 2016年3月12日 下午2:55:42 * @decrition 模拟卖票线程 */ public class Ticket implements Runnable { //当前拥有的票数 private 

Java多线程编程6--单例模式与多线程--单例模式设计详解1

在标准的23个设计模式中,单例设计模式在应用中是比较常见的.但在常规的该模式教学资料介绍中,多数并没有结合多线程技术作为参考,这就造成在使用多线程技术的单例模式时会出现一些意想不到的情况,这样的代码如果在生产环境中出现异常,有可能造成灾难性的后果. 1.立即加载/"饿汉模式" 什么是立即加载?立即加载也称为"饿汉模式",就是使用类的时候已经将对象创建完毕,常见的实现办法就是直接new实例化. 立即加载/"饿汉模式"是在调用方法前,实例已经被创建了

Java多线程编程6--单例模式与多线程--单例模式

单例对象(Singleton)是一种常用的设计模式.在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在.这样的模式有几个好处: 1.)某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销. 2.)省去了new操作符,降低了系统内存的使用频率,减轻GC压力. 3.)有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了.(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程.