Future模式
标签:Java并发

Future模式

对于Future模式,我们在获取一个一个数据的时候,我们可以先开启这个操作,等它执行,它会立即返回一个凭据给我们,然后我们可以接着去做其他的事,当后面我们需要该操作的结果时,我们可以拿着凭据去获取结果。当然,如果这个时候该操作还是没有处理完毕的话,那么线程将会发生阻塞。

下面是一个生活中的实例,我们购物完,快递会给我们一个运单号,我们获取了这个运单号后,可以接着去做其他的事情,当快递到的时候,我们可以根据运单号去取快递,如果我们事做完了,但是快递还没有到的话,那么我们还是得继续等待。

1. 实例

下面使我们自己实现的Future模式

一个数据接口

public interface Data {
    public String getResult();
}

真实的数据对象

public class RelaData implements Data {
    private final String result;

    public RelaData(String result) {
        StringBuffer stringBuffer=new StringBuffer();
        for (int i = 0; i < 10; i++) {
            stringBuffer.append(result);
            try {
                Thread.sleep(250);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.result=stringBuffer.toString();
    }

    @Override
    public String getResult() {
        return result;
    }
}

代理的数据对象,用于返回凭据

public class FutureData implements Data {
//    FutureData包装了RelaData
    protected RelaData relaData=null;
    protected boolean isReady=false;

    public synchronized void setRelaData(RelaData relaData) {
        if (isReady){
            return;
        }
        this.relaData=relaData;
        isReady=true;
        notifyAll();
    }

    @Override
    public synchronized String getResult() {
        while (!isReady){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return relaData.getResult();
    }
}

客户端对象

public class Client {
    public Data request(final String queryStr){
        final FutureData futureData=new FutureData();
        new Thread(){
            @Override
            public void run() {
                RelaData relaData=new RelaData(queryStr);
                futureData.setRelaData(relaData);
            }
        }.start();
        return futureData;
    }
}

Main

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Client client=new Client();
        Data data=client.request("name");
        System.out.println("请求完毕");
        //用休眠代替其他任务的处理
        Thread.sleep(2000);
        System.out.println("dadsada");
        System.out.println("数据:"+data.getResult());
    }
}

这样的话,我们在调用request方法之后,会返回一个FutureData,我们后面就可以根据这个对象去获取result。

2. JDK中的Future模式

对于JDK中的Future模式,我们可以通过RunnableFuture,RunnableFuture的子类有FutureTask,该FutureTask内部有一个Sync类,该类会去委托Callable执行,具体的可以看:Java并发-深入学习 Java 线程池

下面我们将上面的例子进行改造:

真实对象

public class RealData implements Callable<String> {
    private String para;

    public RealData(String para) {
        this.para = para;
    }

    @Override
    public String call() throws Exception {
        StringBuffer stringBuffer=new StringBuffer();
        for (int i = 0; i < 10; i++) {
            stringBuffer.append(para);
            try {
                Thread.sleep(250);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return stringBuffer.toString();
    }
}

该对象的call方法执行操作,并返回数据。

Main

public class FutureMain {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        FutureTask<String> futureTask=new FutureTask<String>(new RealData("a"));
        ExecutorService executorService= Executors.newFixedThreadPool(1);
//        开启线程执行call()方法
        executorService.submit(futureTask);
        System.out.println("请求完毕");
        Thread.sleep(2000);
        System.out.println("dadsada");
//        取得call()的返回值
//        此时call()如果还没有完成的话,则依然会等待
        System.out.println("数据:"+futureTask.get());
    }
}

可见我们是先构造一个FutureTask对象,将实现了Callable接口的对象传进去,最后我们开启线程池执行,然后我们可以去执行其他操作,最后我们通过futureTask的get方法来获取返回值。

  • 3 min read

CONTRIBUTORS


  • 3 min read