美文网首页
多线程设计模式解读—Promise(承诺)模式

多线程设计模式解读—Promise(承诺)模式

作者: 九九派 | 来源:发表于2018-08-12 20:03 被阅读114次

    上次我们讲到多线程设计模式的Guarded Suspension(保护性暂挂模式),Guarded Suspension是条件未满足时线程一直处于等待状态,直到条件满足才继续运行,而在Promise模式中,Promise的getResult方法获取异步任务结果,如果任务未执行完毕,就一直处于等待状态,可以说,Promise模式是Guarded Suspension模式的一个应用实例,它有两个重要角色:Promise,主要用于包装异步任务处理结果;Promisor,用于对外提供返回Promise的异步方法,并启动异步任务。而这里Promise可以直接用JDK 中的Future实现。

    我们先来看一段源码:

    public class FutureTaskMain {
    
      public static void main(String[] args){
    
        //初始化长时计算器
        Future<Integer> calculatorPromise = Calulator.newInstance();
        System.out.println("模拟主线程任务执行开始...");
        System.out.println("模拟主线程任务执行结束...")
      //获取执行结果,
        try {
      //异步操作被封装在了Calculator中
          Integer result = (Integer) calculatorPromise.get(6, TimeUnit.SECONDS);
          System.out.println("长时任务执行完成,结果:"+result);
        } catch (InterruptedException e) {
    //     守护线程阻塞被打断;
          e.printStackTrace();
        } catch (ExecutionException e) {
    //      执行任务时出错;
          e.printStackTrace();
        } catch (TimeoutException e) {
    //     执行超时
          calculatorPromise.cancel(true);
          e.printStackTrace();
        } catch (CancellationException e) {
          //如果线程已经cancel了,再执行get操作会抛出这个异常
          e.printStackTrace();
        }
    
      }
    
    }
    
    
    class Calulator{
      public static Future<Integer> newInstance() {
    
        //创建计算任务,传入FutureTask
        final FutureTask futureTask = new FutureTask(new Callable<Integer>(){
          @Override
          public Integer call() throws Exception {
            System.out.println("模拟长时间计算任务执行中...");
            Thread.sleep(5000);
            Random rand = new Random();
            Integer i = rand.nextInt(900) + 100;
            return i;
          }
        });
    
    
        new Thread(futureTask).start();
    
        return futureTask;
      }
    }
    

    这里FutureTask就是Promise角色,主要用于包装异步任务处理结果,而Calculator是Promisor角色,我们可以看到,Promise模式屏蔽了同步和异步编程的差异,异步操作被封装在了Calculator中,客户端代码像调用同步方法一样直接调用即可,无需关注内部的技术细节。

    有两个需要注意的地方:

    1、异常的处理

    你希望知道Promise执行过程中是否会抛出异常,而它是运行在异步方法中的,Promisor方法并不知道,解决方法是将异常记录在Promise的实例变量中,在返回时检查抛出,不过FutureTask已经帮我们实现了这一步,我们只要处理get返回时抛出的异常即可。

    2、访问过多时会产生大量的线程,增加系统的开销和资源的消耗,因此,可以考虑用FutureTask + ExecutorService的方式,如:

    ExecutorService executorService=Executors.newFixedThreadPool(10);
    executorService.execute(futureTask);
    

    相关文章

      网友评论

          本文标题:多线程设计模式解读—Promise(承诺)模式

          本文链接:https://www.haomeiwen.com/subject/jofovftx.html