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