Java NIO-Selector

Selector(選擇器)是Java NIO中能夠同時(shí)監(jiān)測(cè)多個(gè)Channel通道误辑,并且還能知道Channel上讀寫事件是否準(zhǔn)備好。這樣一個(gè)Selector線程就可以管理多個(gè)Channel沦泌,而不像Blocking IO那樣一個(gè)線程對(duì)應(yīng)一個(gè)監(jiān)管一個(gè)IO事件磷蜀。

Selector特點(diǎn)

一個(gè)Selector對(duì)應(yīng)多個(gè)Channel:僅用單個(gè)線程來(lái)處理多個(gè)Channels的好處是朝捆,只需要更少的線程來(lái)處理通道。事實(shí)上国章,可以只用一個(gè)線程處理所有的通道具钥。對(duì)于操作系統(tǒng)來(lái)說(shuō),線程之間上下文切換的開銷很大液兽,而且每個(gè)線程都要占用系統(tǒng)的一些資源(如內(nèi)存)骂删。因此,使用的線程越少越好四啰。

select宁玫、poll、epoll模式

select柑晒,poll欧瘪,epoll都是IO多路復(fù)用的機(jī)制。I/O多路復(fù)用就通過(guò)一種機(jī)制匙赞,可以監(jiān)視多個(gè)描述符佛掖,一旦某個(gè)描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進(jìn)行相應(yīng)的讀寫操作涌庭。

  1. select模式
    特點(diǎn):忙輪詢芥被,文件描述符有大小限制,會(huì)將整個(gè)文件描述符數(shù)組頻繁在用戶內(nèi)存空間和內(nèi)核的內(nèi)存地址空間的拷貝復(fù)制脾猛,造成較大的性能消耗撕彤。

過(guò)程:不停地從頭到尾遍歷整個(gè)文件描述符,根據(jù)每一個(gè)描述符的狀態(tài)進(jìn)行通知處理猛拴,被通知的線程還需要遍歷整個(gè)文件描述符來(lái)判斷是哪個(gè)事件準(zhǔn)備好了羹铅。

  1. poll模式
    特點(diǎn):輪詢,沒(méi)有文件描述符大小限制(有系統(tǒng)內(nèi)存大小相關(guān))愉昆,但是同樣會(huì)將整個(gè)文件描述符數(shù)組頻繁在用戶內(nèi)存空間和內(nèi)核的內(nèi)存地址空間的拷貝復(fù)制职员,造成較大的性能消耗

過(guò)程:為了避免CPU空轉(zhuǎn),可以同時(shí)觀察許多流的I/O事件跛溉,在空閑的時(shí)候焊切,會(huì)把當(dāng)前線程阻塞掉,當(dāng)有一個(gè)或多個(gè)流有I/O事件時(shí)芳室,就從阻塞態(tài)中醒來(lái)专肪,被喚醒的程序就會(huì)輪詢一遍所有的文件描述符,來(lái)判斷哪個(gè)IO的事件就緒堪侯,并進(jìn)行相應(yīng)的處理嚎尤。

  1. epoll模式
    特點(diǎn):基于IO事件響應(yīng),高性能伍宦,沒(méi)有文件描述符大小限制芽死,只會(huì)將準(zhǔn)備就緒的IO描述符進(jìn)行復(fù)制。

過(guò)程:epoll同時(shí)觀察許多流的I/O事件次洼,在沒(méi)有IO事件發(fā)生時(shí)关贵,會(huì)把當(dāng)前線程阻塞掉,當(dāng)有一個(gè)或多個(gè)流有I/O事件時(shí)卖毁,就從阻塞態(tài)中醒來(lái)揖曾,被喚醒的程序就能獲取所有已經(jīng)準(zhǔn)備就緒的文件描述符,并進(jìn)行相應(yīng)的處理亥啦。

  1. epoll模式的其他特性
  • 在Linux2.6(包括)之后使用epoll模式實(shí)現(xiàn)Java NIO炭剪,在用戶程序使用上是沒(méi)有差別的,只是遍歷Selector.selectedKeys()方法返回集合的時(shí)間復(fù)雜度為O(n)或O(1)禁悠,其中n為整個(gè)文件描述符的數(shù)量念祭。
  • epoll模式的高效性:epoll在被內(nèi)核初始化時(shí)(操作系統(tǒng)啟動(dòng)),同時(shí)會(huì)開辟出epoll自己的內(nèi)核高速cache區(qū)碍侦,用于安置每一個(gè)我們想監(jiān)控的socket粱坤,這些socket會(huì)以紅黑樹的形式保存在內(nèi)核cache里,以支持快速的查找瓷产、插入站玄、刪除。這個(gè)內(nèi)核高速cache區(qū)濒旦,就是建立連續(xù)的物理內(nèi)存頁(yè)株旷,然后在之上建立slab層,簡(jiǎn)單的說(shuō),就是物理上分配好你想要的size的內(nèi)存對(duì)象晾剖,每次使用時(shí)都是使用空閑的已分配好的對(duì)象锉矢,避免了內(nèi)核內(nèi)存空間和用戶內(nèi)存空間的復(fù)制消耗。

Selector的使用

Selector總是和Channel成對(duì)出現(xiàn)的齿尽,與Selector一起使用時(shí)沽损,Channel必須處于非阻塞模式下。這意味著不能將FileChannel與Selector一起使用循头,因?yàn)镕ileChannel不能切換到非阻塞模式绵估。而套接字通道都可以。

從一個(gè)完整的程序示例開始


需要留意的步驟:

步驟3

使用Selector選擇器需要將Channel設(shè)置為非阻塞狀態(tài)卡骂,F(xiàn)ileChannel不可設(shè)置為非阻塞狀態(tài)国裳,套接字可以。

步驟5

注意通常不會(huì)注冊(cè)寫就緒事件全跨,因?yàn)樵诎l(fā)送緩沖區(qū)未滿的情況下始終是可寫的缝左,而且
注冊(cè)寫事件,而又不用寫數(shù)據(jù)螟蒸,則緩沖區(qū)未滿總會(huì)響應(yīng)寫事件就緒盒使,很容易造成CPU空轉(zhuǎn),出現(xiàn)消耗CPU100%的情況七嫌。
注冊(cè)的事件可以為:

  • SelectionKey.OP_CONNECT(某個(gè)channel成功連接到另一個(gè)服務(wù)器稱為“連接就緒”)
  • SelectionKey.OP_ACCEPT(channel準(zhǔn)備好接收新進(jìn)入的連接稱為“接收就緒”少办,對(duì)應(yīng)于ServerSocket.accept方法)
  • SelectionKey.OP_READ(一個(gè)有數(shù)據(jù)可讀的通道可以說(shuō)是“讀就緒”)
  • SelectionKey.OP_WRITE(等待寫數(shù)據(jù)的通道可以說(shuō)是“寫就緒”)

register()方法會(huì)返回一個(gè)SelectionKey對(duì)象

  • interest集合(所選擇的感興趣的事件集合)
  • ready集合(通道已經(jīng)準(zhǔn)備就緒的操作的集合)

這是一個(gè)復(fù)合int類型字段,通過(guò)如下方法可以進(jìn)行判斷
selectionKey.isAcceptable();
selectionKey.isConnectable();
selectionKey.isReadable();
selectionKey.isWritable()

  • Channel诵原、Selector

通過(guò)如下方法獲取觸發(fā)此IO事件的Channel英妓,以及被哪個(gè)Selector監(jiān)聽到的

  • 附加的對(duì)象(可選,是在注冊(cè)Channel時(shí)一同注冊(cè)的一個(gè)對(duì)象)
步驟6.1

通過(guò)select方法獲取通道

select()方法返回的int值表示有多少通道已經(jīng)就緒绍赛。亦即蔓纠,自上次調(diào)用select()方法后有多少通道變成就緒狀態(tài)。如果調(diào)用select()方法吗蚌,因?yàn)橛幸粋€(gè)通道變成就緒狀態(tài)腿倚,返回了1,若再次調(diào)用select()方法蚯妇,如果另一個(gè)通道就緒了敷燎,它會(huì)再次返回1。如果對(duì)第一個(gè)就緒的channel沒(méi)有做任何操作箩言,現(xiàn)在就有兩個(gè)就緒的通道硬贯,但在每次select()方法調(diào)用之間,只有一個(gè)通道就緒了陨收。

  • int select()

select()阻塞到至少有一個(gè)通道在你注冊(cè)的事件上就緒了

  • int select(long timeout)

select(long timeout)和select()一樣饭豹,除了最長(zhǎng)會(huì)阻塞timeout毫秒(參數(shù))

  • int selectNow()

selectNow()不會(huì)阻塞,不管什么通道就緒都立刻返回

如何喚醒阻塞在select方法的線程

  • Selector.wakeup()

將使得選擇器上的第一個(gè)有就緒Channel但是還沒(méi)有返回的選擇操作立即返回。如果當(dāng)前沒(méi)有就緒Channel被選擇拄衰,那么下一次對(duì) select( )方法的一種形式的調(diào)用將立即返回它褪,后續(xù)的選擇操作將正常進(jìn)行。在選擇操作之間多次調(diào)用 wakeup( )方法與調(diào)用它一次沒(méi)有什么不同肾砂。有時(shí)這種延遲的喚醒行為并不是您想要的列赎,您可以通過(guò)在調(diào)用 wakeup( )方法后調(diào)用 selectNow( )方法來(lái)繞過(guò)這個(gè)問(wèn)題宏悦,此時(shí)需要將代碼合理地關(guān)注于返回值和執(zhí)行選擇集合镐确。

  • Selector.close( )

如果選擇器的 close( )方法被調(diào)用,那么任何一個(gè)在選擇操作中阻塞的線程都將被喚醒,與選擇器相關(guān)的通道將被注銷,而鍵將被取消饼煞。通道本身并不會(huì)關(guān)閉源葫。

  • Thread.interrupt( )

拋出中斷異常,程序異常返回砖瞧,如果捕獲異常則進(jìn)行清理操作息堂。

步驟6.3

每次迭代末尾的keyIterator.remove()調(diào)用。

Selector不會(huì)自己從已選擇鍵集中移除SelectionKey實(shí)例块促。必須在處理完通道時(shí)自己移除荣堰。下次該通道變成就緒時(shí),Selector會(huì)再次將其放入已選擇鍵集中竭翠。實(shí)際上在兩次調(diào)用select( )方法之間振坚,都必須手動(dòng)將其清空,換句話說(shuō)斋扰,select( )方法只會(huì)在已有的所選鍵集上添加鍵渡八,它們不會(huì)創(chuàng)建新的建集。

步驟7

先使Selector的注冊(cè)信息失效传货,然后在關(guān)閉Channel

先關(guān)閉Selector屎鳍,然后在關(guān)閉Channel,平滑的關(guān)閉整個(gè)系統(tǒng)问裕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末逮壁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子粮宛,更是在濱河造成了極大的恐慌窥淆,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窟勃,死亡現(xiàn)場(chǎng)離奇詭異祖乳,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)秉氧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門眷昆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事亚斋∽髅模” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵帅刊,是天一觀的道長(zhǎng)纸泡。 經(jīng)常有香客問(wèn)我,道長(zhǎng)赖瞒,這世上最難降的妖魔是什么女揭? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮栏饮,結(jié)果婚禮上吧兔,老公的妹妹穿的比我還像新娘。我一直安慰自己袍嬉,他們只是感情好境蔼,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著伺通,像睡著了一般箍土。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上罐监,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天吴藻,我揣著相機(jī)與錄音,去河邊找鬼笑诅。 笑死调缨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吆你。 我是一名探鬼主播弦叶,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼妇多!你這毒婦竟也來(lái)了伤哺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤者祖,失蹤者是張志新(化名)和其女友劉穎立莉,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體七问,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蜓耻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了械巡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刹淌。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡饶氏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出有勾,到底是詐尸還是另有隱情疹启,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布蔼卡,位于F島的核電站喊崖,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏雇逞。R本人自食惡果不足惜荤懂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望喝峦。 院中可真熱鬧势誊,春花似錦、人聲如沸谣蠢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)眉踱。三九已至,卻和暖如春霜威,著一層夾襖步出監(jiān)牢的瞬間谈喳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工戈泼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留婿禽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓大猛,卻偏偏與公主長(zhǎng)得像扭倾,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挽绩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Java NIO(New IO)是從Java 1.4版本開始引入的一個(gè)新的IO API膛壹,可以替代標(biāo)準(zhǔn)的Java I...
    JackChen1024閱讀 7,536評(píng)論 1 143
  • 作者: 一字馬胡 轉(zhuǎn)載標(biāo)志 【2017-11-24】 更新日志 一、Java OIO Java OIO (Jav...
    一字馬胡閱讀 1,339評(píng)論 0 12
  • 概述 Selector是NIO中實(shí)現(xiàn)I/O多路復(fù)用的關(guān)鍵類唉堪。Selector實(shí)現(xiàn)了通過(guò)一個(gè)線程管理多個(gè)Channe...
    tomas家的小撥浪鼓閱讀 5,277評(píng)論 6 26
  • 參考:http://ifeve.com/selectors/原文地址 目錄 Java NIO教程 Java NIO...
    步積閱讀 4,466評(píng)論 3 10
  • 這兩天了解了一下關(guān)于NIO方面的知識(shí)模聋,網(wǎng)上關(guān)于這一塊的介紹只是介紹了一下基本用法,沒(méi)有系統(tǒng)的解釋NIO與阻塞唠亚、非阻...
    Ruheng閱讀 7,121評(píng)論 5 48