netty(九)初識Netty-Future & Promise 一、簡介 二、擴展了哪些主要能力? 三、使用示例

一、簡介

在netty當中,我們需要進行異步處理的時候,經常會調用以下的兩個方法:

Future & Promise

其實在我們使用JDK的時候,就知道有一個Future接口,用於異步時接收任務結果。

在Netty當中,基於JDK當中的Future接口,進行了擴展;後面又在Netty的Future基礎之上,增加了Promise接口。

關於三者的關係請看以下的類圖:

  • JDK Future:只能同步等待任務結束(無論成功還是失敗)才能得到結果。
  • Netty Future:可以同步等待任務結束得到結果,也可以異步方式得到結果,前提是任務必須要結束。
  • Netty Promise:不僅有 netty Future 的功能,而且脫離了任務獨立存在,只作爲兩個線程間傳遞結果的容器。

二、擴展了哪些主要能力?

在這一章節,主要分析前面提到的netty新增的兩個接口都新增了哪些功能。

功能/名稱 jdk Future netty Future Promise
cancel 取消任務 - -
isCanceled 任務是否取消 - -
isDone 任務是否完成,不能區分成功失敗 - -
get 獲取任務結果,阻塞等待 - -
getNow - 獲取任務結果,非阻塞,還未產生結果時返回 null -
await - 等待任務結束,如果任務失敗,不會拋異常,而是通過 isSuccess 判斷 -
sync - 等待任務結束,如果任務失敗,拋出異常 -
isSuccess - 判斷任務是否成功 -
cause - 獲取失敗信息,非阻塞,如果沒有失敗,返回null -
addLinstener - 添加回調,異步接收結果 -
setSuccess - - 設置成功結果
setFailure - - 設置失敗結果

三、使用示例

下面針對Promise我們重點學習,看看針對不同場景下的使用。

例1 同步處理任務成功

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        DefaultEventLoop eventExecutors = new DefaultEventLoop();
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

        eventExecutors.execute(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() +", set success: " + 10);
            promise.setSuccess(10);
        });

        System.out.println(Thread.currentThread().getName() +", start...");
        //未產生結果,不阻塞,返回null
        System.out.println(Thread.currentThread().getName() +", " + promise.getNow());
        //阻塞等待結果
        System.out.println(Thread.currentThread().getName() +", " + promise.get());
    }

結果:

main, start...
main, null
defaultEventLoop-1-1, set success: 10
main, 10

例2 異步處理任務成功

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        DefaultEventLoop eventExecutors = new DefaultEventLoop();
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

        eventExecutors.execute(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() +", set success: " + 10);
            promise.setSuccess(10);
        });

        System.out.println(Thread.currentThread().getName() +", start...");

        //添加異步監聽,當有結果時調用getNow獲取結果
        promise.addListener(future->{
            System.out.println(Thread.currentThread().getName() +", " + future.getNow());
        });
    }

結果:

main, start...
defaultEventLoop-1-1, set success: 10
defaultEventLoop-1-1, 10

例3 同步處理任務失敗 sync & get

sync或者get,區別是get會對異常信息再包一層

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        DefaultEventLoop eventExecutors = new DefaultEventLoop();
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

        eventExecutors.execute(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() +", set failure");
            promise.setFailure(new RuntimeException());
        });

        System.out.println(Thread.currentThread().getName() +", start...");
        //未產生結果,不阻塞,返回null
        System.out.println(Thread.currentThread().getName() +", " + promise.getNow());
        //阻塞等待結果
        System.out.println(Thread.currentThread().getName() +", " + promise.get());
        //System.out.println(Thread.currentThread().getName() +", " + promise.get());
    }

結果:

main, start...
main, null
defaultEventLoop-1-1, set failure
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.RuntimeException
    at io.netty.util.concurrent.DefaultPromise.get(DefaultPromise.java:349)
    at com.cloud.bssp.netty.promise.Test3.main(Test3.java:34)
Caused by: java.lang.RuntimeException
    at com.cloud.bssp.netty.promise.Test3.lambda$main$0(Test3.java:27)
    at io.netty.channel.DefaultEventLoop.run(DefaultEventLoop.java:54)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:748)

例4 同步處理任務失敗 await

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        DefaultEventLoop eventExecutors = new DefaultEventLoop();
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

        eventExecutors.execute(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() +", set failure");
            promise.setFailure(new RuntimeException());
        });

        System.out.println(Thread.currentThread().getName() +", start...");
        //未產生結果,不阻塞,返回null
        System.out.println(Thread.currentThread().getName() +", " + promise.getNow());
        //阻塞等待結果
        promise.await();
        //isSuccess判斷任務是否成功
        System.out.println(Thread.currentThread().getName() +", " + promise.isSuccess());
    }

結果:

main, start...
main, null
defaultEventLoop-1-1, set failure
main, false

例5 異步處理任務失敗

    public static void main(String[] args) {
        DefaultEventLoop eventExecutors = new DefaultEventLoop();
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

        eventExecutors.execute(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ", set failure");
            promise.setFailure(new RuntimeException());
        });

        System.out.println(Thread.currentThread().getName() + ", start...");

        //添加異步監聽,當有結果時調用getNow獲取結果
        promise.addListener(future -> {
            if (!promise.isSuccess()) {
                //失敗查看結果
                System.out.println(Thread.currentThread().getName() + ", " + promise.cause());
            }
            System.out.println(Thread.currentThread().getName() + ", " + future.getNow());
        });
    }

結果:

main, start...
defaultEventLoop-1-1, set failure
defaultEventLoop-1-1, java.lang.RuntimeException
defaultEventLoop-1-1, null

例6 await 死鎖檢查

    public static void main(String[] args) {
        DefaultEventLoop eventExecutors = new DefaultEventLoop();
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

        eventExecutors.submit(()->{
            System.out.println("1");
            try {
                promise.await();
                // 注意不能僅捕獲 InterruptedException 異常
                // 否則 死鎖檢查拋出的 BlockingOperationException 會繼續向上傳播
                // 而提交的任務會被包裝爲 PromiseTask,它的 run 方法中會 catch 所有異常然後設置爲 Promise 的失敗結果而不會拋出
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("2");
        });
        eventExecutors.submit(()->{
            System.out.println("3");
            try {
                promise.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("4");
        });
    }

結果:

1
2
3
4
io.netty.util.concurrent.BlockingOperationException: DefaultPromise@6a77ffc2(incomplete)
    at io.netty.util.concurrent.DefaultPromise.checkDeadLock(DefaultPromise.java:461)
    at io.netty.util.concurrent.DefaultPromise.await(DefaultPromise.java:246)
    at com.cloud.bssp.netty.promise.Test6.lambda$main$0(Test6.java:21)
    at io.netty.util.concurrent.PromiseTask.runTask(PromiseTask.java:98)
    at io.netty.util.concurrent.PromiseTask.run(PromiseTask.java:106)
    at io.netty.channel.DefaultEventLoop.run(DefaultEventLoop.java:54)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:748)
io.netty.util.concurrent.BlockingOperationException: DefaultPromise@6a77ffc2(incomplete)
    at io.netty.util.concurrent.DefaultPromise.checkDeadLock(DefaultPromise.java:461)
    at io.netty.util.concurrent.DefaultPromise.await(DefaultPromise.java:246)
    at com.cloud.bssp.netty.promise.Test6.lambda$main$1(Test6.java:33)
    at io.netty.util.concurrent.PromiseTask.runTask(PromiseTask.java:98)
    at io.netty.util.concurrent.PromiseTask.run(PromiseTask.java:106)
    at io.netty.channel.DefaultEventLoop.run(DefaultEventLoop.java:54)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:748)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章