java多线程之Future模式

23 篇文章 0 订阅
20 篇文章 0 订阅

一、Future模式

Future的意思是未来、期货,假设有一个方法需要花费很长时间才能获取运行结果,那么,与其一直等待结果,不如先拿一张“提货单”,获取提货单并不耗费时间,这里的“提货单”我们就成为Future角色。

二、示例程序

在Thread-Per-Meaasge模式中,我们知道在每次发出请求时都创建一个线程的示例程序,其中,程序中没有返回值。如:

new Thread() {              public void run() {                  helper.handle(count, c);              }          }.start();

在Future模式中,程序一旦发出请求,就会立即获得返回值,也就说,会有如下的返回值:

Data data = host.request(10, 'A');

这里的返回值data并非请求的运行结果,为了获得请求的运行结果。通过线程会调用data的getContent方法去获取运行结果:

data.getContent();

1.类和接口的一览表

类名说明
Main.java向Host发出请求并获取数据的类
Host.java向请求返回FutureData的实例的类
Data.java表示访问数据的方法的接口,由FutureData和RealData实现该接口
FutureData.java表示RealData的“提货单”的类,其他线程会创建RealData的实例
RealData.java表示实际数据的类,构造函数的处理会花费很长时间

2.示例程序的类图

img

3.实例程序的时序图

img

4.Main.java

package com.viagra.Future_Pattern.Lesson1;

/**
 * @Auther: viagra
 * @Date: 2019/11/19 19:49
 * @Description:
 */
public class Main {
    public static void main(String[] args) {
        /**
         * Main类会调用request方法三次,接着它会接收三个Data(data1、data2、data3)作为返回值
         * 这三个返回值实际上都是FutureData的实例,无需花费时间即可获取它们,类似蛋糕的提货单
         * 然后为了表示Main类去执行了其他操作,我们让其sleep2s,接下来,分别调用之前接收到的返回值data1、data2、data3的getContent方法来获取真正希望获取的结果。
         */
        System.out.println("Main Begin");
        Host host = new Host();
        Data data1 = host.request(10, 'A');
        Data data2 = host.request(20, 'B');
        Data data3 = host.request(30, 'C');
        System.out.println("Main otherJob Begin");

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("data1 = " + data1.getContent());
        System.out.println("data2 = " + data2.getContent());
        System.out.println("data3 = " + data3.getContent());
        System.out.println("Main End");
    }
}

5.Host.java

package com.viagra.Future_Pattern.Lesson1;

/**
 * @Auther: viagra
 * @Date: 2019/11/19 19:49
 * @Description:
 */
public class Host {
    /**
     * 首先会创建FutureData的实例,接着启动一个新的线程并在新线程中创建RealData的实例。
     * 执行request的线程会做一下三件事情:
     * 1.创建FutureData的实例
     * 2.启动一个新线程,用户创建RealData的实例
     * 3.将FutureData的实例作为返回值返回给调用者
     * @param count
     * @param c
     * @return
     */
    public Data request(final int count, final char c) {
        System.out.println("    request( " + count + " , " + c + " ), Begin");
        //(1)创建FutureData的实例
        final FutureData future = new FutureData();

        //(2)启动一个新线程,用户创建RealData的实例
        new Thread(){
            public void run(){
                RealData realData = new RealData(count ,c);
                future.setRealData(realData);
            }
        }.start();
        System.out.println("    request( " + count + " , " + c + " ) End");

        //(3)返回FutureData的实例
        return future;
    }
}

6.Data.java接口

package com.viagra.Future_Pattern.Lesson1;

/**
 * @Auther: viagra
 * @Date: 2019/11/19 19:49
 * @Description:
 */
public interface Data {
    /**
     * Data接口是表示访问数据的方法接口,FurureData类和RealData类实现了该接口
     * @return
     */
    public abstract String getContent();
}

7.FutureData.java

package com.viagra.Future_Pattern.Lesson1;

/**
 * @Auther: viagra
 * @Date: 2019/11/19 19:49
 * @Description:
 */
public class FutureData implements Data {
    /**
     * readData字段是用户保存稍后创建完毕的RealData的实例的字段。
     * ready字段是表示是否已经为readData赋值的字段,如果为true,表示已经为realData赋值。
     * setRealData方法是用户将RealData的实例赋值给realData字段的方法
     * setRealData方法会被Host类的request方法创建新的线程调用
     * getContent是用户获取实际数据的方法。
     */
    private RealData realData = null;
    private boolean ready = false;

    public synchronized void setRealData(RealData realData) {
        if (ready) {
            return;
        }
        this.realData = realData;
        this.ready = true;
        notifyAll();
    }

    public synchronized String getContent() {
        while (!ready) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return realData.getContent();
    }
}

8.RealData.java

package com.viagra.Future_Pattern.Lesson1;

/**
 * @Auther: viagra
 * @Date: 2019/11/19 19:49
 * @Description:
 */
public class RealData implements Data {
    /**
     * 是一个需要花费很长时间才能创建实例的类。
     * getContent方法的处理仅仅是返回content字段的内容
     */
    private final String content;

    public RealData(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) {
                e.printStackTrace();
            }
        }
        System.out.println("    making RealData ( " + count + " , " + c + " ) End");
        this.content = new String(buffer);
    }

    public String getContent() {
        return content;
    }
}

9.运行示例程序

Main Begin
    request( 10 , A ), Begin
    request( 10 , A ) End
    request( 20 , B ), Begin
    request( 20 , B ) End
    request( 30 , C ), Begin
    making RealData ( 10 , A ) Begin
    making RealData ( 30 , C ) Begin
    request( 30 , C ) End
Main otherJob Begin
    making RealData ( 20 , B ) Begin
    making RealData ( 10 , A ) End
data1 = AAAAAAAAAA
    making RealData ( 20 , B ) End
data2 = BBBBBBBBBBBBBBBBBBBB
    making RealData ( 30 , C ) End
data3 = CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
Main End

3.Future模式中的角色

1.Client(请求者)

Client角色向Host角色发出请求(request)并会立即接收到请求的处理结果(返回值),是实例程序中的Main类。

2.Host

Host角色会创建新的线程,并开始在新线程中创建ReakData角色,同时,它会将Future角色返回给Clinet角色,是示例程序中的Host类。

3.VirtualData(虚拟数据)

VirtualData角色是让Future角色与RealData角色具有一致性的角色,是示例程序中的Data接口。

4.RealData(真实数据)

ReakData角色是表示真是数据的角色,是示例程序中的RealData类。

5.Futrue(期货)

Future角色是RealData角色的“提货者”,由Host角色传递给Client角色,从程序行为上看,对Client角色而言,Future角色就是VirtureData角色。是示例程序中的FutureData类。

6.Future模式的类图

img
代码案例

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值