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