Promise-在Java中以同步的方式异步编程

java Promise

java promise(GitHub)是Promise A+规范的java实现版本。Promise A+是commonJs规范提出的一种异步编程解决方案,比传统的解决方案—回调函数和事件—更合理和更强大。promise实现了Promise A+规范,包装了java中对多线程的操作,提供统一的接口,使得控制异步操作更加容易。实现过程中参考文档如下:

基本使用:

<repositories>
    <repository>
      <id>wjj-maven-repo</id>
      <url>https://raw.github.com/zhanyingf15/maven-repo/master</url>
    </repository>
</repositories>
复制代码
<dependency>
  <groupId>com.wjj</groupId>
  <artifactId>promise</artifactId>
  <version>1.0.0</version>
</dependency>
复制代码
IPromise promise = new Promise.Builder().promiseHanler(new PromiseHandler() {
    @Override
    public Object run(PromiseExecutor executor) throws Exception {
        return 2*3;
    }
}).build();

复制代码

上面的例子中创建了一个promise对象,指定PromiseHandler实现,在run方法中写具体的业务逻辑,类似于Runable的run方法。promise对象一经创建,将立即异步执行。推荐使用lambda表达式,更加简洁。

IPromise promise = new Promise.Builder().promiseHanler(executor -> {
    return 2*3;
}).build();
复制代码

获取promise的执行结果通常使用两个方法thenlisten,前者是阻塞的后者是非阻塞的。then方法返回一个新的promise对象,因此支持链式调用。

new Promise.Builder().promiseHanler(executor -> {//promise0
    return 2*3;
}).build().then(resolvedData -> {//返回一个新的promise1
    System.out.println(resolvedData);
    return (Integer)resolvedData+1;
}).then(res2->{
    System.out.println(res2);
    //创建一个新的promise2并返回
    return new Promise.Builder().externalInput(res2).promiseHanler(executor -> {
        return (Integer)executor.getExternalInput()+2;
    }).build();
}).then(res3->{
    System.out.println(res3);
    return res3;
});
复制代码

从上面可以看到promise0、promise1和Promise2是链式调用的,每一次then方法都返回一个新的promise。在then方法的回调中,如果返回的是一个非promise对象,那么promise被认为是一个fulfilled状态的promise,如果返回的是一个promsie实例,那么该实例将会异步执行。
假如需要异步顺序执行a->b-c->d四个线程,调用顺序如下

new PromiseA()
.then(dataA->new PromiseB())//A的回调
.then(dataB->new PromiseC())//B的回调
.then(dataC->new PromiseD())//C的回调
.then(dataD->xxx)//D的回调
.pCatch(error->xxxx)//捕获中间可能产生的异常
复制代码

具体使用 方式参考promise-java异步编程解决方案

Docs

promise规范

promise规范可以参考 Promise A+规范。其中ES6 Promise对象 在Promise A+规范上做了一些补充。java promise在使用上基本与ES6 Promise对象保持一致,部分地方有些许不同,后面会做出说明。 Promise的三个状态

  • pending:等待态,对应线程未执行或执行中
  • fulfilled:完成态,对应线程正常执行完毕,其执行结果称为终值
  • rejected:拒绝态,对应线程异常结束,其异常原因称为拒因
    状态转移只能由pending->fulfilled或pending->rejected,状态一旦发生转移无法再次改变。
Promise

Promise是IPromise的实现,Promise实例一经创建,将立即异步执行,部分接口如下

IPromise then(OnFulfilledExecutor onFulfilledExecutor)
  • 如果当前promise处于pending状态,阻塞当前线程,等待promise状态转变为fulfilled或rejected
  • 如果处于fulfilled状态,执行onFulfilledExecutor.onFulfilled(resolvedData)回调。
    • 如果回调返回一个Promise对象a,以a作为then方法的返回值,如果回调返回一个普通对象obj,以obj作为终值、状态为fulfilled包装一个新Promise作为then方法的返回值
    • 如果执行回调过程中产生异常e,返回一个以e作为拒因、状态为rejected的新Promise,并拒绝执行接下来的所有Promise直到遇到pCatch。
  • 如果处于rejected状态,执行onRejectedExecutor.onRejected(rejectReason)回调,返回一个以当前promise的异常作为拒因、状态为rejected的新Promise,并拒绝执行接下来的所有Promise直到遇到pCatch或pFinally
    参数:
IPromise pCatch(OnCatchedExecutor onCatchedExecutor);

then(null,onRejectedExecutor)的别名,但返回不同于then,出现异常时可以选择不拒绝接下来Promise的执行,可用于异常修正,类似于try{}catch{}
该方法会尝试捕获当前promise的异常,最终返回一个新Promise,当被捕获Promise处于不同的状态时有不同的行为

  • pending:阻塞当前线程,等待pending转变为fulfilled或rejected,行为同then
  • fulfilled:不执行回调,以当前Promise终值和状态返回一个全新的Promise
  • rejected:执行onCatched(Throwable catchReason)回调。
    • 如果onCatched方法返回一个Promise,以这个Promise作为最终返回。
    • 如果onCatched方法返回一个非Promise对象obj,以obj作为终值、fulfilled状态返回一个全新的对象。
    • 如果执行回调过程中产生异常e,以e为拒因、状态为rejected返回一个新的Promise,并拒绝执行接下来的所有Promise直到再次遇到pCatch
void listen(OnCompleteListener onCompleteListener);

指定一个监听器,在promise状态转为fulfilled或rejected调用,该方法不会阻塞线程执行,可以多次调用指定多个监听器

void pFinally(OnCompleteListener onCompleteListener);

listen的别名,行为同listen

Status getStatus()

获取promise的当前状态

Object getResolvedData()

获取promise fulfilled状态下的终值,其余状态下时为null

Throwable getRejectedData()

获取promise rejected状态下的拒因,其余状态下为null

Future getFuture()

获取promise对应异步任务的future

boolean cancel()

尝试取消promise对应的异步任务,底层调用future.cancel(true)。fulfilled或rejected状态下无效。

Promise.Builder

Promise对象生成器

Builder pool(ExecutorService threadPool)

指定一个线程池用于执行promise任务,如果不指定,每一个promise都将启动一个线程

Builder promiseHanler(PromiseHandler promiseExecutor)

指定promise执行器,在promiseHanler的run方法中实现线程的具体业务逻辑,注意==promise对象一经创建,将立即执行其中的逻辑==

Builder externalInput(Object externalInput)

向Promise注入一个外部参数,可以在指定PromiseHandler时通过PromiseExecutor.getExternalInput()获取

int i = 3;
IPromise p = new Promise.Builder()
.externalInput(i).promiseHanler(new PromiseHandler() {
    public Object run(PromiseExecutor executor) {
        Integer args = (Integer) executor.getExternalInput();
        return args*2;
    }
}).build();
复制代码
Builder promise(IPromise promise)

指定一个promise x,使当前promise接受 x 的状态

  • 如果 x 处于pending, 当前promise 需保持为pending直至 x 转为fulfilled或rejected
  • 如果 x 处于fulfilled,用x的终值值执行当前promise,可以在指定PromiseHandler时通过PromiseExecutor.getPromiseInput()获取
  • 如果 x 处于拒绝态,用相同的据因拒绝当前promise执行
ExecutorService fixedPool = Promise.pool(1);
IPromise promise1 = new Promise.Builder().pool(fixedPool).promiseHanler(executor->3).build();
IPromise promise2 = new Promise.Builder().pool(fixedPool)
    .promise(promise1)
    .promiseHanler(executor->4+(Integer) executor.getPromiseInput())
.build()
.then(resolvedData->{
    System.out.println(resolvedData);
    return resolvedData;
}, rejectedReason-> rejectedReason.printStackTrace());
复制代码

最终结果返回7,。如果promise1在执行过程中抛出异常e,promise2将被拒绝执行,将会以e作为拒因,状态为rejected返回一个新的Promise,最终会执行rejectedReason-> rejectedReason.printStackTrace()回调。

IPromise build()

创建一个Promise实例

Promise的静态方法
static IPromise all(IPromise ...promises)

将多个 Promise 实例p1,...pn,包装成一个新的 Promise 实例 p,只有当p1-pn的状态都转为fulfilled时,p的状态才为fulfilled,此时p1-pn的返回值包装为一个数组Object[r1,...rn]作为p的终值。
只要p1-pn中任意一个被rejected,p的状态就转为rejected,将第一个被rejected的promise的拒因作为p的拒因,并尝试取消其余promise的执行(内部调用future.cancel(true))

static IPromise race(IPromise ...promises)

将多个 Promise p1,...pn实例,包装成一个新的 Promise 实例 p,只要p1-pn有一个状态发生改变,p的状态立即改变。并尝试取消其余promise的执行(内部调用future.cancel(true))
第一个改变的promise的状态和数据作为p的状态和数据

static IPromise resolve()

创建一个终值为null、fulfilled状态的promise

static IPromise resolve(Object object)

创建一个终值为object、fulfilled状态的promise

static IPromise resolve(Object object,List args)

将object的then方法以异步方式执行,then方法的执行结果作为Promise的终值

static IPromise resolve(Object object,String methodName,List args)

将object的指定方法以异步方式执行,该方法的执行结果作为Promise的终值,目标方法的参数必须按顺序包含在List中,如object.doSomething(int a,Map b),用resolve执行为

List args = new ArrayList()
args.add(1);
args.add(map)
Promise.resolve(object,"doSomething",args);
复制代码
static IPromise reject(Object reason)

创建一个拒因为reason、rejected状态的promise

static IPromise pTry(Object object,String methodName,List args)

将object的指定方法以同步方式执行,该方法的执行结果作为Promise的终值,如果object为IPromise实例,将忽略methodName和args参数,异步执行该实例。
该方法是以Promise统一处理同步和异步方法,不管object是同步操作还是异步操作,都可以使用then指定下一步流程,用pCatch方法捕获异常,避免开发中出现以下情况

try{
  object.doSomething(args1,args2);//可能会抛出异常
  promise.then(resolvedData->{
      //一些逻辑
  }).then(resolvedData->{
      //一些逻辑
  }).pCatch(e->{
      //异常处理逻辑
  })
}catch(Exception e){
  //异常处理逻辑
}
复制代码

使用pTry,可以简化异常处理

List args = new ArrayList(){args1,args2};
Promise.pTry(object,"doSomething",args)
.then(resolvedData->{
      //一些逻辑
}).then(resolvedData->{
  //一些逻辑
}).pCatch(e->{
  //异常处理逻辑
})
复制代码
PromiseHandler

定义异步逻辑的接口

Object run(PromiseExecutor executor)throws Exception;

run方法中实现具体的业务逻辑,最终run方式是在线程的call方法执行,如果run方法中含有wait、sleep...等锁操作,可能需要自行处理InterruptedException。因为该线程可能被外部调用cancel()或interrupt()方法

PromiseExecutor

promise状态处理

void resolve(final Object args)

将Promise对象的状态从“未完成”变为“成功”(即从pending变为fulfilled)。注意该方法一经调用,promise状态将不可改变,如下例,在调用executor.resolve(3);后,return之前抛出一个异常,promise的状态依旧是fulfilled,终值为3。

new Promise.Builder().promiseHanler(new PromiseHandler(){
    @Override
    public Object run(PromiseExecutor executor) {
        executor.resolve(3);
        throw new RuntimeException("error");
        return null;
    }
}).build()
复制代码

在run方法中executor.resolve(3)等同于return 3

@Override
public Object run(PromiseExecutor executor) {
    return 3;
}
复制代码

大多数情况下建议直接使用return返回promise的终值。

void reject(final Throwable args)

将Promise对象的状态从“未完成”变为“失败”(即从pending变为fulfilled)

Object getExternalInput()

获取通过new Promise.Builder().externalInput(Object externalInput)方法注入的参数,具体参考Promise.Builder#externalInput(Object externalInput)

Object getPromiseInput()

获内部promise的执行结果。通过new Promise.Builder().promise(promise1)指定的promise1的执行结果。具体参考 Promise.Builder#promise(IPromise promise)

OnFulfilledExecutor

fulfilled回调接口

Object onFulfilled(Object resolvedData)throws Exception;

状态转为fulfilled时的回调,返回值可以是IPromise实例或普通对象。如果object是IPromise实例,object作为then方法的返回值,如果object是个普通对象,以object作为终值、状态为fulfilled包装一个新Promise作为then方法的返回值

OnRejectedExecutor

rejected回调接口

void onRejected(Throwable rejectReason)throws Exception;

当Promise转变为rejected状态时的回调

OnCatchedExecutor

rejected回调接口

Object onCatched(Throwable catchReason)throws Exception;

当发生异常时的回调,最终返回一个Promise或普通对象,如果是一个普通对象,这个对象将作为下一个Promise的终值

OnCompleteListener
void listen(Object resolvedData,Throwable e);

当Promise执行结束时的回调(无论是fulfilled还是rejected)

  • resolvedData fulfilled状态时的终值,rejected状态时为null
  • e rejected状态时的异常信息,fulfilled状态时为null
示例
示例1:基本使用
new Promise.Builder().promiseHanler(new PromiseHandler(){
    @Override
    public Object run(PromiseExecutor executor) {
        executor.resolve(3);//返回异步执行结果3
        return null;
    }
}).build().then(new OnFulfilledExecutor() {
    @Override
    public Object onFulfilled(Object resolvedData) {
        Integer i = ((Integer)resolvedData)+1;//获取上一个promsie执行结果3,执行+1
        System.out.println(i);//输出执行结果4
        //创建一个新的promise,将4作为该promise的输入
        IPromise p = new Promise.Builder().externalInput(i).promiseHanler(new PromiseHandler() {
            @Override
            public Object run(PromiseExecutor executor) {
                //获取外部输入4
                Integer args = (Integer) executor.getExternalInput();
                executor.resolve(args*2);//执行 4x2
                return null;
            }
        }).build();
        return p;//返回该promise p
    }
})
.then(new OnFulfilledExecutor() {//执行p的回调
    @Override
    public Object onFulfilled(Object args) {
        System.out.println(args);//输出p的执行结果
        return args;
    }
}, new OnRejectedExecutor() {//捕获可能出现的异常
    @Override
    public void onRejected(Throwable rejectedReason) throws Exception {
        rejectedReason.printStackTrace();
    }
});
复制代码

结果

4
8
复制代码
示例2
ExecutorService fixedPool = Promise.pool(1);//创建一个线程池
//创建promise1
IPromise promise1 = new Promise.Builder().pool(fixedPool).promiseHanler(executor->3).build();
//创建promise2
IPromise promise2 = new Promise.Builder().pool(fixedPool)
    .promise(promise1)//让promise2接受promise1的状态,优先执行promise1
    .promiseHanler(executor->{
        //获取promise1的执行结果,执行promise2的逻辑
        return 4+(Integer) executor.getPromiseInput();
    })
    .build()
    .then(resolvedData->{
        System.out.println(resolvedData);//打印promise2的执行结果 
        return resolvedData;
    }, rejectedReason-> rejectedReason.printStackTrace());
System.out.println("end");
fixedPool.shutdown();
复制代码

结果

7
end
复制代码
示例3:错误处理
new Promise.Builder().promiseHanler(executor -> 3).build().then(resolvedData->{
    System.out.println("a:"+resolvedData);
    return new Promise.Builder().promiseHanler(executor -> {
        executor.reject(new RuntimeException("err"));//抛出异常
        return null;
    }).build();
}).then(resolvedData1 -> {//fulfilled回调
    System.out.println("b:"+resolvedData1);
    return resolvedData1;
},rejectReason -> {//rejected回调
    System.err.println("c:"+rejectReason);
});
复制代码

结果

a:3
c:java.lang.RuntimeException: err
复制代码
示例4:pCatch
new Promise.Builder().promiseHanler(executor -> 0).build()
  .then(res0->{
    System.out.println("a:"+res0);//输出 a:0
    Thread.sleep(100);
    return 1;//返回1
}).then(res1 -> {
    throw new RuntimeException("throw error");//抛出异常
}).then(res2->{
    Thread.sleep(100);
    System.out.println("b:"+res2);
    return 2;
}).pCatch(e->{
    Thread.sleep(100);
    System.out.println("c:");//输出c:
    e.printStackTrace();
    return 3;
}).then(res3->{
    Thread.sleep(100);
    System.out.println("d:"+res3);//输出d:3
    return 4;
});
复制代码

结果

a:0
c:
runtimeException:throw error
d:3
复制代码

从上面结果可以看出,在res1出抛出异常后,拒绝了res2处的执行,被pCatch捕获,pCatch返回3,被包装成终值为3、fulfilled状态的promise,在res3打印d:3。

示例5:Promise.all(IPromise ...promises)
IPromise p1 = new Promise.Builder().promiseHanler(executor -> {
    Thread.sleep(1000);
    return 1;
}).build();
IPromise p2 = new Promise.Builder().promiseHanler(executor -> {
    Thread.sleep(4000);
    return 2;
}).build();
IPromise p3 = new Promise.Builder().promiseHanler(executor -> {
    Thread.sleep(2000);
    return 3;
}).build();
long s = System.currentTimeMillis();
Promise.all(p1,p2,p3).then(resolvedData -> {
    Object[] datas = (Object[])resolvedData;
    for(Object d:datas){
        System.out.println(d);
    }
    return null;
},e->e.printStackTrace());
System.out.println("耗时:"+(System.currentTimeMillis()-s));
复制代码

结果

1
2
3
耗时:4033
复制代码
示例6:线程取消
Map<String,Boolean> p1Flag = new HashMap<>();
p1Flag.put("flag",true);
IPromise p1 = new Promise.Builder().externalInput(p1Flag).promiseHanler(executor -> {
    while (((Map<String,Boolean>)executor.getExternalInput()).get("flag")){
        //do something
        System.out.println("p1 正在执行任务");
    }
    System.out.println("p1任务完成,正常结束");
    return 1;
}).build();
IPromise p2 = new Promise.Builder().promiseHanler(executor -> {
    while (!Thread.currentThread().isInterrupted()){
        System.out.println("执行p2正常逻辑");
    }
    System.err.println("p2线程被取消");
    return 2;
}).build();
IPromise p3 = new Promise.Builder().promiseHanler(executor -> {
    Thread.sleep(10);
    throw new RuntimeException("p3抛出异常");
}).build();
IPromise p4 = new Promise.Builder().finalPromise("4",true).build();
long s = System.currentTimeMillis();
Promise.all(p1,p2,p3,p4).then(resolvedData -> {
    Object[] datas = (Object[])resolvedData;
    for(Object d:datas){
        System.out.println(d);
    }
    return null;
},e->e.printStackTrace());
System.out.println("耗时:"+(System.currentTimeMillis()-s));
p1Flag.put("flag",false);
复制代码

可能的结果如下

p1 正在执行任务
p1 正在执行任务
执行p2正常逻辑
执行p2正常逻辑
p1 正在执行任务 
runtimeException:p3抛出异常
p2线程被取消
p1 正在执行任务
p1 正在执行任务
p1 正在执行任务 
p1任务完成,正常结束
复制代码

从上面结果可以看出,开始p1和p2都在正常执行,当p3抛出异常后,Promise.all方法立即返回p3的异常并打印,同时取消p1和p2的执行,由于p2判断了线程状态Thread.currentThread().isInterrupted(),所以p2执行了正常的退出逻辑。p1仍然在执行,并没有被取消掉,最后打印p1任务完成,正常结束是因为程序末尾执行了p1Flag.put("flag",false);,否则p1会永远循环打印。

示例7:同步方法异步执行
public class ThenTest {
    public Integer then(int a,int b){
        //打印当前执行现场名称
        System.out.println(Thread.currentThread().getName());
        return a+b;
    }
    public static void main(String[] args){
        //打印主线程名称
        System.out.println(Thread.currentThread().getName());
        List arg = new ArrayList<>();
        arg.add(1);
        arg.add(2);
        //将ThenTest实例then方法异步执行
        Promise.resolve(new ThenTest(),arg).then(resolvedData -> {
            System.out.println(resolvedData);
            return resolvedData;
        }).pCatch(e->{
            e.printStackTrace();
            return 1;
        });
    }
}
复制代码

结果

main
promise-thread-0
3
复制代码

转载于:https://juejin.im/post/5b126065e51d4506bd72b7cc

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值