成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【自己讀源碼】Netty4.X系列(四) Netty中的異步調(diào)用

Flands / 524人閱讀

摘要:今天是小明女朋友的生日,小明想給她一個(gè)驚喜,于是想到了訂一個(gè)蛋糕給她,所以小明打電話給蛋糕店預(yù)定,店員回復(fù)他說好的,我們知道了,制作好了會通知你的。于是小明就開開心心的打游戲去了。值檢查,整個(gè)設(shè)計(jì)中均沒有對對象做的檢查,容易引起。

Netty中的異步調(diào)用

如果大家觀察仔細(xì),會發(fā)現(xiàn)我們之前所寫的代碼都是串行執(zhí)行的,這是什么意思?就是我們看到代碼是什么順序,最后程序就是按什么順序執(zhí)行的。

但是Netty作為一個(gè)高性能網(wǎng)絡(luò)框架,他的調(diào)用很多都是異步的,這樣,就可以不等上一步做完,繼續(xù)行進(jìn)下一步,達(dá)到多任務(wù)并行的作用。

實(shí)現(xiàn)概述

Netty是怎么實(shí)現(xiàn)他的異步調(diào)用呢,大致總結(jié)了下由以下幾個(gè)核心部分
組成:

異步執(zhí)行(executor)

異步結(jié)果(future and promise)

Listener

同步接口

首先,既然是異步調(diào)用,肯定要有異步執(zhí)行,同學(xué)們這里肯定想到的是使用線程,沒錯(cuò),他的底層確實(shí)也是線程,只不過netty自身封裝成了executor,增強(qiáng)了線程的調(diào)度。

其次,是要能獲取到這次執(zhí)行的結(jié)果,有的同學(xué)可能會說使用callable,沒錯(cuò)這確實(shí)是一種解決方案,但是netty并沒有使用這種,而是使用了一種更為巧妙的設(shè)計(jì)(也就是通過promise對象來傳遞執(zhí)行的結(jié)果)來完成這種操作,下面我們會詳細(xì)說明。

最后就是promise對象提供的各種接口,比如Listener:可以監(jiān)聽執(zhí)行的完成?;蛘呤峭浇涌?保證異步執(zhí)行的方法順序也是同步的。這篇文章中,我們主要就講這兩,三個(gè),其他的各位童鞋可以自己去看源碼。

Executor實(shí)現(xiàn)

Netty中每個(gè)Channel都有一個(gè)eventloop對象,實(shí)現(xiàn)還蠻復(fù)雜的,在這里不是重點(diǎn),所以我們先實(shí)現(xiàn)一個(gè),具有異步調(diào)用功能的exector。

自定義executor很簡單,只要實(shí)現(xiàn)Executor接口就行

public class MyNettyExecutor implements Executor {
private ThreadFactory factory;

public MyNettyExecutor(ThreadFactory factory) {
    this.factory = factory;
}

public void execute(Runnable command) {
    factory.newThread(command).start();
}
}

然后在需要使用的時(shí)候,實(shí)例化這個(gè)類,這里為了增強(qiáng)使用,我們在類內(nèi)部提供一個(gè)靜態(tài)初始化方法,并提供最簡單factory實(shí)現(xiàn)。

 public static Executor newExecutor(){
        return new MyNettyExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r);
            }
        });
    }
Promise詳解 對furture/promise的理解

我對future的認(rèn)識最開始源于Java的FutureTask框架,簡單來說,F(xiàn)utureTask是Future接口的一種實(shí)現(xiàn),F(xiàn)uture則是異步執(zhí)行的結(jié)果。
而promise,從接口注釋上來看,是一種可修改的Future

/**
 * Special {@link Future} which is writable.
 */

那么現(xiàn)在來看,一個(gè)異步結(jié)果的程序主要有下面幾步

生成promise對象

具體調(diào)用的地方傳入promise參數(shù)

異步調(diào)用完成后,設(shè)置promise為完成

返回future對象

其中,第三步是發(fā)生在異步調(diào)用里的,所以我們看到的順序其實(shí)就是1->2>4,讓我們來畫一張圖。

這其實(shí)可以用一個(gè)現(xiàn)實(shí)中的例子來講述。

今天是小明女朋友的生日,小明想給她一個(gè)驚喜,于是想到了訂一個(gè)蛋糕給她,所以小明打電話給蛋糕店預(yù)定,店員回復(fù)他說:好的,我們知道了,制作好了會通知你的。于是小明就開開心心的打游戲去了。

在上面的例子中,預(yù)定蛋糕就是一個(gè)異步過程,我只要通知需要做這件事的人(execute),并拿到回復(fù)(Future),然后就可以做其他事情了。然后過一段時(shí)間打電話詢問蛋糕做好沒(isDone),如果沒做好,那就請他做好的時(shí)候通知我(listener)

所以現(xiàn)在我們有了異步執(zhí)行,還需要什么呢?

Future和Promise的定義接口

Promise實(shí)現(xiàn)

然后,我們理一下需要哪些接口

isDone 判斷任務(wù)是否完成

addListener

trySuccess 設(shè)置任務(wù)完成并通知所有l(wèi)istener

sync 同步方法,等待任務(wù)完成

定義

首先定義接口

/*listener接口,提供complete方法**/
public interface MyFutureListener>  extends EventListener {

    void operationComplete(F future);
}
/*Future接口**/
public interface MyFuture {

    boolean isDone();

    MyFuture sync() throws InterruptedException ;

    MyFuture addListener(MyFutureListener> listener);


}
/*promise接口**/
public interface MyPromise extends MyFuture{

    boolean trySuccess();

    @Override
    MyPromise addListener(MyFutureListener> listener);


}
isDone

我們假設(shè)只有完成和未完成兩個(gè)狀態(tài),Promise內(nèi)維護(hù)著這個(gè)狀態(tài)值(初始為null),那么判斷是否完成只需要判斷這個(gè)值不為空就行了。

    private volatile Object result = null;

    @Override
    public boolean isDone() {
        return result != null;
    }
trySucess

那么最簡單的success實(shí)現(xiàn)就是給這個(gè)對象賦值

    @Override
    public boolean trySuccess() {
        result = new Object();
        return true;
    }

當(dāng)然,這里很不嚴(yán)謹(jǐn),我們后面再說。

Listener接口實(shí)現(xiàn)

上面我們定義了listener接口,這里要實(shí)現(xiàn)addListener方法

    private List>> listeners;

@Override
    public MyPromise addListener(MyFutureListener> listener) {
        synchronized (this) {
            if(listeners == null){
                listeners = new ArrayList>>();
                listeners.add(listener);
            }else {
                listeners.add(listener);
            }
        }
        if (isDone()){
            for (MyFutureListener f: listeners
                    ) {
                f.operationComplete(this);
            }
        }
        return this;
    }

然后完善下success方法,成功的時(shí)候調(diào)用每一個(gè)listener的complete方法。

@Override
    public boolean trySuccess() {
        result = new Object();

        for (MyFutureListener f: listeners
             ) {
            f.operationComplete(this);
        }

        return true;
    }
同步接口實(shí)現(xiàn)

同步也很簡單,就是先判斷任務(wù)是否完成,沒有完成就wait一下。注意,wait之前我們要保持同步,引入synchronized原語。

@Override
    public MyFuture sync() throws InterruptedException {
        if (isDone()){
            return this;
        }
       
         synchronized (this){
            while (!isDone()) {
            waiters++;
                try {
                    wait();
                }finally {
                    waiters--;
                }
            }
        }
      
        return this;
    }

同理,需要有地方去喚醒它,我們繼續(xù)完善success方法,最終我們的trySuccess方法如下

private synchronized void checkNotify(){
        if (waiters > 0){
            notifyAll();
        }
    }

 @Override
    public boolean trySuccess() {
        result = new Object();
        checkNotify();
        for (MyFutureListener f: listeners
             ) {
            f.operationComplete(this);
        }

        return true;
    }
Demo

輪子造好了,是時(shí)候?qū)憘€(gè)demo測試一下

public class MyExecutorDemo {
    public static void main(String[] args) {

        MyFuture future = asyncHello().addListener((MyFutureListener>) future1 -> System.out.println("監(jiān)聽到完成"));
        if (future.isDone()){
            System.out.println("異步執(zhí)行完成");
        }else{
            try {
                future.sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static MyFuture asyncHello(){
        Executor executor = MyNettyExecutor.newExecutor();
        final DefaultPromise promise = new DefaultPromise();
        executor.execute(() -> {
            System.out.println("Hello Async");
            try {
                //模擬一些操作
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            promise.trySuccess();
        });
        return promise;
    }
}
警告

不可用于生產(chǎn),這個(gè)Future/promise的設(shè)計(jì)僅僅為了說明異步執(zhí)行和結(jié)果,距離netty中的異步框架還缺少很多。

NULL值檢查,整個(gè)設(shè)計(jì)中均沒有對對象做NULL的檢查,容易引起NullPointException。

異常處理缺失,對可能失敗的地方做異常處理(這也是是否能用于生產(chǎn)的合格檢驗(yàn))

非完全異步,listener的通知沒有使用異步

待補(bǔ)充(以我現(xiàn)在的水平,暫時(shí)想不到)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/68619.html

相關(guān)文章

  • 自己源碼Netty4.X系列(三) Channel Register

    摘要:我想這很好的解釋了中,僅僅一個(gè)都這么復(fù)雜,在單線程或者說串行的程序中,編程往往是很簡單的,說白了就是調(diào)用,調(diào)用,調(diào)用然后返回。 Netty源碼分析(三) 前提概要 這次停更很久了,原因是中途迷茫了一段時(shí)間,不過最近調(diào)整過來了。不過有點(diǎn)要說下,前幾天和業(yè)內(nèi)某個(gè)大佬聊天,收獲很多,所以這篇博文和之前也會不太一樣,我們會先從如果是我自己去實(shí)現(xiàn)這個(gè)功能需要怎么做開始,然后去看netty源碼,與...

    darkbug 評論0 收藏0
  • 自己源碼Netty4.X系列(二) 啟動類成員Channel

    摘要:下面無恥的貼點(diǎn)源碼。啟動類我們也學(xué),把啟動類抽象成兩層,方便以后寫客戶端。別著急,我們慢慢來,下一篇我們會了解以及他的成員,然后,完善我們的程序,增加其接收數(shù)據(jù)的能力。文章的源碼我會同步更新到我的上,歡迎大家,哈哈。 廢話兩句 這次更新拖了很長時(shí)間,第一是自己生病了,第二是因?yàn)樽铋_始這篇想寫的很大,然后構(gòu)思了很久,發(fā)現(xiàn)不太合適把很多東西寫在一起,所以做了點(diǎn)拆分,準(zhǔn)備國慶前完成這篇博客。...

    waterc 評論0 收藏0
  • 自己源碼Netty4.X系列(一) 啟動類概覽

    摘要:一些想法這個(gè)系列想開很久了,自己使用也有一段時(shí)間了,利用也編寫了一個(gè)簡單的框架,并運(yùn)用到工作中了,感覺還不錯(cuò),趁著這段時(shí)間工作不是很忙,來分析一波源碼,提升下技術(shù)硬實(shí)力。 一些想法 這個(gè)系列想開很久了,自己使用netty也有一段時(shí)間了,利用netty也編寫了一個(gè)簡單的框架,并運(yùn)用到工作中了,感覺還不錯(cuò),趁著這段時(shí)間工作不是很忙,來分析一波源碼,提升下技術(shù)硬實(shí)力。 結(jié)構(gòu) 這里先看下net...

    qingshanli1988 評論0 收藏0
  • Netty4.x 源碼實(shí)戰(zhàn)系列):Pipeline全剖析

    摘要:在上一篇源碼實(shí)戰(zhàn)系列三全剖析中,我們詳細(xì)分析了的初始化過程,并得出了如下結(jié)論在中,每一個(gè)都有一個(gè)對象,并且其內(nèi)部本質(zhì)上就是一個(gè)雙向鏈表本篇我們將深入源碼內(nèi)部,對其一探究竟,給大家一個(gè)全方位解析。 在上一篇《Netty4.x 源碼實(shí)戰(zhàn)系列(三):NioServerSocketChannel全剖析》中,我們詳細(xì)分析了NioServerSocketChannel的初始化過程,并得出了如下結(jié)論...

    13651657101 評論0 收藏0
  • Netty4.x 源碼實(shí)戰(zhàn)系列(二):服務(wù)端bind流程詳解

    摘要:對于,目前大家只知道是個(gè)線程組,其內(nèi)部到底如何實(shí)現(xiàn)的,它的作用到底是什么,大家也都不太清楚,由于篇幅原因,這里不作詳細(xì)介紹,后面會有文章作專門詳解。 在上一篇《ServerBootstrap 與 Bootstrap 初探》中,我們已經(jīng)初步的了解了ServerBootstrap是netty進(jìn)行服務(wù)端開發(fā)的引導(dǎo)類。 且在上一篇的服務(wù)端示例中,我們也看到了,在使用netty進(jìn)行網(wǎng)絡(luò)編程時(shí),我...

    laoLiueizo 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<