LOG.info("*************************WINDOWS系統*********************************"); //設置事件處理 serverBootstrap.childHandler(nettyServerInitializer); windowFuture = serverBootstrap.bind(nettyConfig.getPort()); windowFuture.channel().closeFuture().sync();
netty啟動的時候
windowFuture = serverBootstrap.bind(nettyConfig.getPort())方法后加sync,后邊的代碼是會被執行的,
但是
windowFuture.channel().closeFuture().sync();這個代碼之后的代碼不會被執行,比較迷惑
sync方法找到根里是如下源碼
public Promise<V> sync() throws InterruptedException { this.await(); this.rethrowIfFailed(); return this; }
接下來是來自一位大牛的博客內容https://blog.csdn.net/benluobobo/article/details/53870347
Netty 學習 - 異步操作中的Future和Promise
本文繼續介紹Netty的相關知識,主要講解異步操作中的Future和Promise
由於Netty中的Future都是異步IO操作,結果是未知的,因此命名為ChannelFuture,表示跟Channel的操作有關
ChannelFuture提供了一系列不同於JDK Future的API,用於獲取操作結果,添加事件監聽器,取消IO操作,同步等待。
Netty強烈建議直接通過添加監聽器的方式獲取IO結果,而不是通過同步等待的方式
如果用戶操作調用了sync或者await方法,會在對應的future對象上阻塞用戶線程,例如future.channel().closeFuture().sync()
而最終觸發future對象的notify動作都是通過eventLoop線程輪詢任務完成的,例如對關閉的sync,因為不論是用戶直接關閉或者eventLoop的輪詢狀態關閉,都會在eventLoop的線程內完成notify動作,所以不要在IO線程內調用future對象的sync或者await方法,因為應用程序代碼都是編寫的channelHandler,而channelHandler是在eventLoop的線程內執行的,所以是不能在channelHandler中調用sync或者await方法的
對於Future而言,提供的API有get與get(timeout) 前者是一直阻塞的get方法,后者帶了超時時間,具體實現方式是在Future上執行wait方法,將當前運行線程進行阻塞,達到阻塞效果,而后通過eventLoop線程對Future對象進行notifyAll,保證喚醒阻塞的線程
而Future只有獲取查詢的API,類似於JDK中的Future,為了擴展對異步結果的寫操作,Netty提供了Promise,繼承於Future,可以用於設置IO操作的結果,在AbstratChannel的代碼中可以看到對相關的IO操作都會新建Promise作為具體IO函數的參數,這樣就能異步立即返回Promise,當IO操作后續發生異常或者完成時,將會設置promise的結果,在設置結果的過程中,包括以下三步
1 設置result的值
2 notifyAll,喚醒在本Promise上等待的線程
3 回調listener
下面以最常見的關閉等待操作為例,在大部分的網上例子中都會有如下的代碼:
Channel channel = b.bind(8080).sync().channel();
channel.closeFuture().sync();
那么下面的channel.closeFuture().sync()實際是如何工作
channel.closeFuture()不做任何操作,只是簡單的返回channel對象中的closeFuture對象,對於每個Channel對象,都會有唯一的一個CloseFuture,用來表示關閉的Future,
所有執行channel.closeFuture().sync()就是執行的CloseFuturn的sync方法,從上面的解釋可以知道,這步是會將當前線程阻塞在CloseFuture上
一般來說,編寫以上代碼的都是在Main線程中用來啟動ServerBootStrap的,所以Main線程會被阻塞,保證服務端Channel的正常運行
那么什么時候Main線程會被喚醒繼續執行呢
在channel中有close方法,當調用close方法后,會按照pipeline.close - tail.close - head.close - unsafe.close - abstractChannel.doClose0
private void doClose0(ChannelPromise promise) {
try {
doClose();
closeFuture.setClosed();
safeSetSuccess(promise);
} catch (Throwable t) {
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
其中doClose方法是抽象方法,用來真正關閉IO連接,例如javaChannel.close
第二步則是用來處理CloseFuture的關閉,setClosed會執行trySuccess,這樣就會在CloseFuture對象上執行notifyAll以及回調listener等,喚醒Main線程
第三步則是用來處理用戶Future,前面說過在AbstratChannel的代碼中可以看到對相關的IO操作都會新建Promise作為具體IO函數的參數,例如對於channel.close方法,分別有參數的方法和沒有參數的方法,沒有參數的方法實際在底層會自動new一個promise用來異步的返回結果,也可以在應用程序中主動編寫一個Promise用來處理應用邏輯
在Promise對象上執行
@Override
public boolean trySuccess(V result) {
if (setSuccess0(result)) {
notifyListeners();
return true;
}
return false;
}
其中setSuccess0中會有 checkNotifyWaiters();的步驟,喚醒在該Promise對象上等待的線程,再notifyListeners進行回調Listener,完成設置動作
---------------------
作者:benluobo
來源:CSDN
原文:https://blog.csdn.net/benluobobo/article/details/53870347
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!