netty---sync,await


  

 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
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM