Netty inEventLoop方法?異步回調?Promise?


inEventLoop

一直對這個方法不是很理解,衆所周知是判斷當前線程是不是在當前的EventLoop中對應的那個線程?
一個channel對應一個且只對應一個EventLoop,一個Channel對應一個且只對應一個Pipeline,Pipline中包含handler(也是context),當前的Handler被Channel調用,那什麼時候執行這段代碼的線程不是channel對應的那個EventLoop中的線程?

EventExecutor中最關鍵的是inEventLoop方法,用於判斷一個線程是否是EventExecutor內部那個線程,EventExecutor和EventLoop都是單線程實現。inEventLoop的主要使用場景是,當IO變化時,通過channel關聯的pipeline會觸發對應的事件,這些事件對應的執行pipeline中的處理鏈中handler的回調方法,每個handler添加到pipeline都可以指定自己的EventLoop,如果沒指定,默認使用要添加的pipeline關聯的channel註冊到的EventLoopGroup中的某個EventLoop。所以channel通過pipeline調用handler時,如果handler沒有單獨指定EventLoop,那inEventLoop就會返回true,他倆由同一個線程處理,直接調用handler。如果handler單獨指定了EventLoop,inEventLoop就會返回false,channel調用handler時就把要調用的方法封裝到Runnable裏,然後添加到handler指定的EventLoop的任務隊列裏,稍後會由對應的EventLoop中的線程執行。

來自:https://www.jianshu.com/p/d39ff4c98c5f

至於代碼分析就不貼代碼了,沒有什麼特別的,關鍵是情況的分析。

自己畫了個圖方便理解,當然肯定還有不對的地方,理解的不是很好,有問題希望提出共同進步!
在這裏插入圖片描述
所以會有下面兩種情況
在這裏插入圖片描述

在handler中:
executor.inEventLoop()?
當前executor是channel對應的那個eventLoop,而inEventLoop中的currentThread是handler自定義的eventLoop,是不相等的。所以是false,false的時候將handler中的回調封裝成task放到自己對應的eventLoop的任務隊列中

這就是異步

當前的channel相當於是主線程,主線程想要回調,發現當前的handler有自己的處理線程,那麼就把回調方法封裝成task給他自己的Executor中的queue中,他自己去執行吧,我該幹嘛幹嘛去了。

爲什麼返回Promise

阿西,實在不想貼代碼
平常用戶代碼習慣這麼寫:

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
	ChannelFuture future = ctx.writeAndFlush("test data");
	future.addListener(new ChannelFutureListener() {
			@Override
			public void operationComplete(ChannelFuture future) throws Exception {
			if (future.isSuccess()){
				System.out.println("寫出成功");
			}else{
				System.out.println("寫出失敗");
			}
		}
	});
}

爲什麼writeAndFlush返回future,下面通過future調用addListener?
在writeAndFlush方法中返回了promise,也就是future
在這裏插入圖片描述
在addListener方法中有一個isDone方法
在這裏插入圖片描述
然後isDone0
在這裏插入圖片描述
判斷result狀態,這個result狀態就是DefaultPromise中的,在writeAndFlush中flush也能修改這個狀態,所以是在writeAndFlush和addListener中相同的。

Promise繼承自Future,Future中有isSuccess方法
在這裏插入圖片描述
所以在operationComplete方法中能夠執行future.isSuccess(),即這個promise(也就是futrure)是writeAndFlush和addListener的一個橋樑,分享着當前是否能夠回調的狀態(是不是寫完了)

這理解其實和JDK JUC中的Future是一個意思了:
promise(也就是futrure)中的result也是一個狀態值,如果writeAndFlush完成了,設置值success,並且去主動喚醒,或者在addListener中主動喚醒。
區別就是Future中是通過get方法被動喚醒的,所以時機可能不是那麼的準確。

另外jdk中的futrue方法是通過get阻塞進行的,runnable通過run生產數據,Future通過get獲取數據,FuturetTask被兩者共享,繼承自他們兩個,擁有了run和get這兩個功能,在自導自演,run中執行callable的call方法,執行完成設置可執行標誌,沒有完成則標誌還是未完成的,get方法一直阻塞,可是如果已經生產好了,而沒有get呢?所以在Netty中通過listener這種方法更加精準的添加了監聽,能夠第一時間回調。
在這裏插入圖片描述

拾遺


什麼是異步?
是否要等待一個操作的完成?

什麼是阻塞?
是否要等待一個數據準備好?


當然在Netty中還有一個比較有意思的:

WriteAndFlush和addListener方法,如果是異步的,在writeAndFlush之前,完成了AddListener,那麼在WriteAndFlush執行完write有異常回調,或者,執行完flush回調operationComplete的時候,設置爲了Success,是可以放心回調的。
可是如果是兩個方法如果是同步執行,當然異步執行也可能,writeAndFlush執行完了,result設置爲了Success,但是AddListener還沒有添加,那要怎麼回調?operationComplete還沒有準備好呢。通過看源碼能夠知道notifyListenersNow的時候,先判斷listeners(其實就是listener)是不是沒有,沒有直接return了,那不就意味着這次wirteAnfFlush事件沒有回調了? 其實在AddListener方法中,會進行一次判斷,判斷當前的result是不是Success,是的話就會進行一次回調。
代碼分析略。


還有ByteBuf的緩存和命中也應該細細體會。


聲明:
筆者本身還是一個小白,只看到了冰山一角,不一定完全正確,如果文中存在嚴重的錯誤,還請不吝指出,不僅利於自己的修正,同時也減少他人產生對於知識的誤解。

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