java selector 源码_Java NIO核心组件-Selector和Channel
昨天我們介紹了一下SelectorProvider和IO multiplexing.特別是IO multiplexing中的epoll系統調用,是Linux版本的Java的NIO的核心實現.
那今天我們就來介紹一下, Java NIO中的核心組件, Selector和Channel.這兩個組件,對于熟悉Java OIO,而不熟悉Java NIO的朋友來說,理解其作用是極其不易的.
前提條件
在閱讀這篇文章之前,如果各位不熟悉甚至沒有聽說過IO multiplexing中的epoll,請務必花時間去了解一下.了解了它們之后,就很容易理解Java NIO的實現了.
這里我們講解的是Linux版本且內核版本大于2.6的Java NIO的實現,對于其他的系統或者內核版本較低的Java NIO,其具體實現是不一樣的.
舉例來說, Linux 內核版本大于等于2.6的Java NIO是采用epoll來實現的.而Linux內核版本小于2.6的Java NIO,則是采用poll來實現的.
Selector和Channel
Selector和Channel的關系,如下圖所示:
各位如果了解過epoll的話,應該知道epoll_create操作會創建一個需要被監聽的file descriptor.然后,epoll_ctl操作會為告訴內核,需要監聽一個file descripitor的什么事件.最后,使用epoll_wait來告訴內核開始監聽.
這里我們就可以把Selector比作epoll中的內核.把Channel比作epoll_create操作創建的file descriptor.這樣就很容易理解了吧.
因為Java NIO實際上是給我們對IO multiplexing進行了封裝,隱藏了其底層的實現.所以我們完全可以這樣來理解.
貼出在Java NIO tutorial中看到的一個圖片,
對于這張圖片,我實在是不能茍同其說法.我們可以看到,在這張圖片中,我們可以看到,一個線程中只有一個Selector,每個Selector負責監控三個Channel.而實際上,一個線程中,并不是必須只能有一個Selector.一個Selector也不是只能注冊三個Channel.
在AbstractSelector的源碼中,我們可以看到,實際上它只維護了一個不再監聽的Channel的集合:
我們查看具體的Selector的父類,SelectorImpl,中的register方法的實現.跟具體的Selector實現相關的類,在JDK提供的src.zip源碼包中是找不到的.這里使用CFR反編譯器反編譯rt.jar包.從中找到其實現.
我們可以看到,它會把Channel進一步封裝成SelectionKeyImpl.然后使用implRegister方法來實現具體的注冊過程.從SelectorImpl的源碼中,我們同樣可以看到,implRegister方法是一個抽象方法,需要其子類來實現具體的注冊過程.
這里我們感興趣的子類是EPollSelectorImpl,我們查看其源碼,可以看到其中維護了一個從file descriptor到SelectionKeyImpl的Map.我們剛剛也提到了,SelectionKeyImpl中,包裝了一個Channel,
我們從EPollSelectorImpl的implRegister方法中,也沒有看到會對Map這個表示EPollSelectorImpl維護的Channel的Map進行尺寸限制的操作.即并沒有限制一個EPollSelectorImpl可以注冊的Channel的數量.
反而是在Channel中,維護了它向Selector注冊時,Selector給其返回的SelectionKey的集合.相當于維護了它已經注冊的Selector的集合.
我們查看AbstractSelectableChannel的向Selector注冊的源碼:
我們可以看到,它會把Selector給它返回的SelectionKey加入到上面我們說過的那個集合中,我們看看addKey()方法的具體實現:
在這里我們就可以看到,默認情況下,Channel會創建一個容量為3的表示它注冊的Selector的集合.當它需要向更多的Selector注冊時,則對這個集合進行擴容.
而并沒有提到一個Selector中最多可以注冊多少個Channel.
總結
以上是生活随笔為你收集整理的java selector 源码_Java NIO核心组件-Selector和Channel的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 15年前乔布斯改变世界:初代iPhone
- 下一篇: 雷军:IMX989采用4:3比例 比相机