java多线程设计模式笔记之Future Pattern

        想象一个场景,你去蛋糕店买蛋糕,先下订单之后,店员给你一张提货单,叫你下午来取货,下午你来取蛋糕,如果此时蛋糕已经做好了,则拿走蛋糕,如果没有做好,则你还得再等等。相对应的程序场景,主线程要得到某些数据需要耗时操作,于是开了个子线程去生产数据,然后主线程去做别的事,等一段时间之后再去取回数据,实现了异步回调。

    看代码~~

首选是Data接口,表示数据:

public interface Data {
    String getContent();
}

因为会有两个Data实现类,一个是提货单FutureData,一个是蛋糕RealData,Data接口的作用是为了和客户端解耦,客户端只知道要的是Data,并不需要知道具体有多少种Data。

蛋糕RealData:

public class RealData implements Data{
    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");
        content = new String(buffer);
    }

    @Override
    public String getContent() {
        return content;
    }
}

这里只是进行一个耗时的简单字符数组赋值操作,这里用sleep故意产生耗时效果。


提货单FutureData:

public class FutureData implements Data{

    private RealData realData = null;
    private boolean ready = false;//realData是否准备好了的标志位

    public synchronized void setRealData(RealData realData){
        //如果已经准备好了,则直接返回
        if (ready){
            return;
        }
        //将真正的data赋值之后,将ready标志位置位
        this.realData = realData;
        ready = true;
        notifyAll();
    }



    @Override
    public synchronized String getContent() {
        //如果realData还没有做好,则线程等待
        if (!ready){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return realData.getContent();
    }
}

你拿着提货单要拿蛋糕的时候,店员说还没做好蛋糕(ready为false),你只好等待(wait),当店员做好蛋糕的时候,他叫你来拿蛋糕(notifyAll),这时你就可以拿回蛋糕(返回数据)。



专门负责开子线程的Host:

public class Host {
    public Data request(final int count, final char c){
        System.out.println("request"+"("+count +","+c+")BEGIN");
        final FutureData futureData = new FutureData();

        new Thread(){
            @Override
            public void run() {
                RealData realData = new RealData(count,c);
                futureData.setRealData(realData);
            }
        }.start();

        return futureData;
    }
}

开子线程生产RealData(耗时操作),等到RealData生产完成,就赋值到FutureData实例中。

注意到在request方法中,立刻返回的是FutureData.


客户端程序:

public class Main {
    public static void main(String args[]){
        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 do other job");
        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");
    }
}

  因为Host的request返回的是FutureData实例,所以并不能在返回之后马上拿到想要的数据,在一段时间做其他处理之后,

调用Data实例(这里是返回的FutureData)的getContent方法,在FutureData代码中可以看到,getContent会先判断

RealData是否已经被生产出来,如果还没有,则主线程还需在此等待,直到RealData已经产生。如果RealData已经被生产出来、

则立刻获取结果。

最后看下运行结果:

main Begin
request(10,a)BEGIN
request(20,b)BEGIN
request(30,c)BEGIN
main do other job
making RealData(30,c)BEGIN
making RealData(10,a)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

只有在RealData创建出来之后,主线程才可以将RealData实例的content读取出来。

发布了69 篇原创文章 · 获赞 76 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/sinat_23092639/article/details/53353640