CompletableFuture的async后缀函数与不带async的函数的区别

async函数

thenApply
thenApplyAsync

thenAccept
thenAcceptAsync

whenComplete
whenCompleteAsync
等等等等

不带async的函数的动作比较复杂

只要下面两个例子看懂了,就行了。

public class Lession07 {

    private final static Logger logger = LoggerFactory.getLogger(Lession07.class);

    public static void main(String[] args) throws Exception {
        CompletableFuture<Integer> f = new CompletableFuture<Integer>();

        new Thread(() -> {
            // 子线程A启动
            logger.info("子线程A启动");
            try {
                logger.info("子线程A沉睡5s");
                Thread.sleep(5000l);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info("子线程A令future完成");
            f.complete(100);  // 当子线程A执行到f.complete的时候,会去看是否有注册好的f的then或者when(非async的),如果有的话,会顺次去执行。
            logger.info("子线程A结束");
        }).start();;


        // 当前线程(主线程)执行到这里的时候,如果子线程还没有执行到f.complete(100),
        // 那么当前线程会把whenComplete事件注册起来,并且说好哪个线程执行了f.complete(100),
        // 哪个线程就负责执行whenComplete的内容。
        // 如果当前线程(主线程)执行到这里的时候,f.complete(100)已经被其他线程执行完毕了。
        // 那么只有当前线程自己来执行whenComplete里面的内容了。
        f.whenComplete((i, ex) -> {
            // 这个场景下,whenComplete的回调的执行线程会是子线程A
            logger.info("do something after complete begin");
            try {
                logger.info("沉睡10s");
                Thread.sleep(10000l);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info("do something after complete end");
        });


        logger.info("main over");
        System.in.read();

    }

}

以上程序打出的log如下:

20:33:40.389 [Thread-0] INFO com.wzm.opcua.lesson.Lession07 - 子线程A启动
20:33:40.395 [main] INFO com.wzm.opcua.lesson.Lession07 - main over
20:33:40.396 [Thread-0] INFO com.wzm.opcua.lesson.Lession07 - 子线程A沉睡5s
20:33:45.399 [Thread-0] INFO com.wzm.opcua.lesson.Lession07 - 子线程A令future完成
20:33:45.400 [Thread-0] INFO com.wzm.opcua.lesson.Lession07 - do something after complete begin
20:33:45.400 [Thread-0] INFO com.wzm.opcua.lesson.Lession07 - 沉睡10s
20:33:55.403 [Thread-0] INFO com.wzm.opcua.lesson.Lession07 - do something after complete end
20:33:55.403 [Thread-0] INFO com.wzm.opcua.lesson.Lession07 - 子线程A结束

让我们把主线程注册whenComplete的时机放慢一点,放到子线程A已经执行完f.complete之后。如下:

public class Lession07 {

    private final static Logger logger = LoggerFactory.getLogger(Lession07.class);

    public static void main(String[] args) throws Exception {
        CompletableFuture<Integer> f = new CompletableFuture<Integer>();

        new Thread(() -> {
            // 子线程A启动
            logger.info("子线程A启动");
            try {
                logger.info("子线程A沉睡5s");
                Thread.sleep(5000l);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info("子线程A令future完成");
            f.complete(100);  // 当子线程A执行到f.complete的时候,会去看是否有注册好的f的then或者when(非async的),如果有的话,会顺次去执行。
            logger.info("子线程A结束");
        }).start();;


        // 当前线程(主线程)执行到这里的时候,如果子线程还没有执行到f.complete(100),
        // 那么当前线程会把whenComplete事件注册起来,并且说好哪个线程执行了f.complete(100),
        // 哪个线程就负责执行whenComplete的内容。
        // 如果当前线程(主线程)执行到这里的时候,f.complete(100)已经被其他线程执行完毕了。
        // 那么只有当前线程自己来执行whenComplete里面的内容了。

        try {
            logger.info("主线程沉睡10s");
            Thread.sleep(10000l);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        f.whenComplete((i, ex) -> {
            // 这个场景下,whenComplete的回调的执行线程会是主线程
            logger.info("do something after complete begin");
            try {
                logger.info("沉睡10s");
                Thread.sleep(10000l);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            logger.info("do something after complete end");
        });


        logger.info("main over");
        System.in.read();

    }

}

log输出如下:

20:41:40.200 [Thread-0] INFO com.wzm.opcua.lesson.Lession07 - 子线程A启动
20:41:40.203 [main] INFO com.wzm.opcua.lesson.Lession07 - 主线程沉睡10s
20:41:40.205 [Thread-0] INFO com.wzm.opcua.lesson.Lession07 - 子线程A沉睡5s
20:41:45.207 [Thread-0] INFO com.wzm.opcua.lesson.Lession07 - 子线程A令future完成
20:41:45.207 [Thread-0] INFO com.wzm.opcua.lesson.Lession07 - 子线程A结束
20:41:50.212 [main] INFO com.wzm.opcua.lesson.Lession07 - do something after complete begin
20:41:50.212 [main] INFO com.wzm.opcua.lesson.Lession07 - 沉睡10s
20:42:00.215 [main] INFO com.wzm.opcua.lesson.Lession07 - do something after complete end
20:42:00.215 [main] INFO com.wzm.opcua.lesson.Lession07 - main over

结论

f的whenComplete的内容由哪个线程来执行,取决于哪个线程X执行了f.complete()。但是当X线程执行了f.complete()的时候,whenComplete还没有被执行到的时候(就是事件还没有注册的时候),那么X线程就不会去同步执行whenComplete的回调了。这个时候哪个线程执行到了whenComplete的事件注册的时候,就由哪个线程自己来同步执行whenComplete的事件内容。

而whenCompleteAsync的场合,就简单很多。一句话就是线程池里面拿一个空的线程或者新启一个线程来执行回调。和执行f.complete的线程以及执行whenCompleteAsync的线程无关。

猜你喜欢

转载自blog.csdn.net/leon_wzm/article/details/80560081