基于JAVA的Promise模式实现

Promise模式是一种异步编程模式,即咱们能够先开始一个任务,拿到这个任务的凭据而并不须要当即获得这个任务的执行结果才继续往下执行,咱们拿着这个凭证能够在以后任何须要的时候去兑换结果。这篇文章主要介绍一种基于JAVA的Promise模式实现并结合一些例子。前端


原始实现java

为了可以让你们对这个模式有个印象,我举个简单点的例子,假如咱们正在作百度百科这个页面,咱们须要给前端提供一个服务(下面的代码咱们将结果打印出来来模拟),能够根据id获取百科条目的内容,具体的例子是咱们想要获取某个明星的百度百科信息。而这个明星的信息有两个相关内容可能须要调用别人的服务来获取,一个是获取明星相关的人物信息;另外一个是获取这个明星相关的新闻。咱们假设这两个服务分别位于不一样的业务部门,并且因为业务的复杂性,服务比较慢,我用下面的代码来表示:git

/**
 * @author float.lu
 */
public class OldLongCallExample {
    public static void main (String ...s) {
        long start = System.nanoTime();
        //280ms
        String result1 = getRelatedRoles();
        //250ms
        String result2 = getRelatedNews();
        System.out.println("Result:" + result1 + result2);
        System.out.println("take:" + TimeUnit.NANOSECONDS.toMillis((System.nanoTime() - start)) + "ms");
    }

上面的代码咱们能够看出,咱们首先调用getRelatedRoles获取明星相关人物,这里须要花费280ms,拿到明星相关人物以后咱们继续调用getRelatedNew获取明星相关新闻,这里须要250ms,咱们总共须要约530ms,这个时间是很长的。编程


思考promise

其实对于上面的这种状况,咱们在调用getRelatedRoles以后其实并不须要等待getRelatedRoles给出结果以后在往下进行,由于后面花费时间较长的部分getRelatedNews并不依赖于getRelatedRoles的结果,所以咱们顺利成章的认为咱们能够在调用getRelatedRoles以后不须要等待,咱们继续调用getRelatedNews,当主方法须要返回的时候咱们再分别取拿getRelatedRoles和getRelatedNews的结果,这就是本文基于Promise模式的实现要解决的事情。异步


基于JPromise的实现ide

JPromise是基于JAVA的Promise的实现,在抽象类Promise中咱们主要提供了三个抽象方法:异步编程

/**
 * 获取执行结果
 * @return
 */
public abstract V get();

/**
 * 带超时时间的获取执行结果
 * @param timeout
 * @param unit
 * @return
 */
public abstract V get(long timeout, TimeUnit unit);

/**
 * 获取异常信息
 * @return
 */
public abstract Throwable getException();

和一个将普通代码逻辑包装成Promise的工具方法:工具

/**
 * 将普通逻辑包装成Promise
 * @param task
 * @param <V>
 * @return
 */
public static <V> Promise<V> wrap(final AsyncTask<V> task){
    if (executorService == null) {
        setDefaultExecutorService();
    }
    return new DefaultPromise<V>(executorService.submit(new Callable<V>() {
        @Override
        public V call() throws Exception {
            return task.call();
        }
    }));
}

咱们经过JPromise能够将不一样的业务逻辑包装成Promise对象,咱们把Promise对象称做凭证,经过Promise抽象类提供的get或get(timeout,unit)方法来在须要的时候根据凭证获取结果,同时容许超时。那么最开始的实现能够改形成下面的样子:测试

/**
 * @author float.lu
 */
public class PromiseLongCallExample {
    public static void main (String ...s) {
        long start = System.nanoTime();
        //提交任务不须要当即拿到结果
        Promise<String> resolve1 = Promise.wrap(new AsyncTask<String>() {
            @Override
            public String call() throws Exception {
                return getRelatedRoles();
            }
        });
        //提交任务不须要当即拿到结果
        Promise<String> resolve2 = Promise.wrap(new AsyncTask<String>() {
            @Override
            public String call() throws Exception {
                return getRelatedNews();
            }
        });

        System.out.println("Result:" + resolve1.get() + resolve2.get());
        System.out.println("take:" + TimeUnit.NANOSECONDS.toMillis((System.nanoTime() - start)) + "ms");
    }

通过测试,上面的代码执行时间约为280ms,相比最开始的530ms获得了很大的优化。


异常捕获

一般异步执行的逻辑都会面临着异常捕获的问题,Jpromise的实现将逻辑异常捕获并经过getException向外面提供访问接口。


自定义线程池

基于JPromise的异步任务都是由额外的线程执行的,所以咱们须要为JPromise配置线程池。JPromise支持用户自定义线程池,包括基于Spring容器的配置,只须要将自定义的ExecutorService注入到PromiseFigure的executorService属性便可。


总结

Promise模式的适用场景也是有限的,当下层逻辑不依赖于上层逻辑,这些逻辑一般是串行执行的时候可使用Promise模式来进行优化,优化效果仍是很显著的。


项目地址:https://git.oschina.net/floatlu/jpromise

相关文章
相关标签/搜索