JAVA NIO 翻譯系列(六、Selector)

selector是一個(gè)檢測(cè)一個(gè)或者多個(gè)channel的組件,能偵測(cè)哪個(gè)channel裝備好寫或者讀操作。這種方式下,一個(gè)單線程就可以管理多個(gè)channel或者多個(gè)網(wǎng)絡(luò)鏈接。


為什么使用selector?

使用單線程去處理多channel的優(yōu)勢(shì)就是你只需要少量的線程去處理多channel。甚至,你可以用一個(gè)線程去處理所有的channel。對(duì)操作系統(tǒng)來說,線程切換是很費(fèi)資源的,并且在操作系統(tǒng)中,每個(gè)線程都會(huì)占據(jù)資源(內(nèi)存),因此線程越少,越好。

但請(qǐng)記住,現(xiàn)代的操作系統(tǒng)和cpu在多任務(wù)處理上正變的越來越好,多線程花費(fèi)的時(shí)間越來越少。實(shí)際上,如果一個(gè)cpu是多核的,你不做多任務(wù)處理的話,可能正是一種資源浪費(fèi)。總之,這塊屬于不同區(qū)域的討論。僅對(duì)此處而言,一個(gè)selector可以用一個(gè)縣城來處理多個(gè)Channel。


Java NIO: A Thread uses a Selector to handle 3 Channel's

Creating a Selector

創(chuàng)建一個(gè)selector:

Selector selector = Selector.open();


注冊(cè)channel到Selector上:


使用selector的前提就是channel必須是在非阻塞的模式下。這就意味著你不能將FileChannel注冊(cè)到selector上,前面文章的例子都是FileChannel。但是Socket 相關(guān)的channel就能很好的使用selector。

注意register方法的第二個(gè)參數(shù),

這是一個(gè)有趣的設(shè)置,意味著這個(gè)channel通過selector對(duì)什么事件感興趣,有以下四個(gè)事件可以監(jiān)聽到:

? ? ?Connect ? ? Accept ? ? Read ? ?Write

一個(gè)Channel啟動(dòng)一個(gè)事件代表它為這個(gè)事件轉(zhuǎn)備好了。因此,channel鏈接上服務(wù)器就是一個(gè)連接準(zhǔn)備,一個(gè)socket Channel接受一個(gè)連接代表接受事件,一個(gè)channel有數(shù)據(jù)準(zhǔn)備去讀代表一個(gè)準(zhǔn)備讀事件。

如果一個(gè)selector對(duì)多個(gè)事件感興趣,則

int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

傳入到register方法中。


SelectionKey

register()方法的返回對(duì)象就是SelectionKey。SelectionKey含有幾個(gè)有意思的特性;



Interest Set

通過以下方法可以獲得register()方法的時(shí)候的事件類型

你可以使用&連接符連接SelectionKey的常量來找出Selector對(duì)哪些事件感興趣

Ready Set

ready set 是channel的一些列可操作的狀態(tài)集合,你可以獲取這個(gè)狀態(tài)集合通過一個(gè)selection。

int readySet = selectionKey.readyOps();

下面的方法跟上面的效果一樣

selectionKey.isAcceptable();

selectionKey.isConnectable();

selectionKey.isReadable();

selectionKey.isWritable();


Channel + Selector

你可以通過SelectionKey來訪問Channel和Selector對(duì)象

Channel? channel? = selectionKey.channel();

Selector selector = selectionKey.selector();


Attaching Objects

你可以在selectionKey附加一個(gè)Object對(duì)象,來標(biāo)識(shí)channel對(duì)象以便找出你要的channel對(duì)象,或者附加一些其他的信息。舉個(gè)栗子,你可以將buffer對(duì)象附加在上面

selectionKey.attach(theObject);

Object attachedObj = selectionKey.attachment();

你可以在注冊(cè)Selector的時(shí)候把對(duì)象附加上去

SelectionKey key = channel.register(selector, SelectionKey.OP_READ, theObject);


Selecting Channels via a Selector

一旦你注冊(cè)了一個(gè)或者多個(gè)channel到一個(gè)Selector上面,你就可以調(diào)用以下三個(gè)select方法。這些方法會(huì)返回準(zhǔn)備好的事件的對(duì)象,這些事件(connect,accept,read 或者write)都是你當(dāng)初注冊(cè)Selector時(shí)候傳遞的。換句話說如果你注冊(cè)的時(shí)候是傳遞的讀事件,那么當(dāng)你調(diào)用select的時(shí)候,獲得當(dāng)前準(zhǔn)備去讀的channels。

int select()

int select(long timeout)

int selectNow()

select()會(huì)阻塞,直到至少一個(gè)已經(jīng)轉(zhuǎn)備好事件的channel。

select(long timeout)?跟上面方法一樣,除了他會(huì)在timeout毫秒內(nèi)會(huì)阻塞.

selectNow()不會(huì)阻塞,會(huì)立即返回


selectedKeys()

當(dāng)你調(diào)用select()方法的時(shí)候,返回的值代表有多少個(gè)channel準(zhǔn)備好了,你可以通過selected key set去訪問準(zhǔn)備好的channel

Set selectedKeys = selector.selectedKeys();

When you register a channel with aSelectortheChannel.register()method returns aSelectionKeyobject. This key represents that channels registration with that selector. It is these keys you can access via theselectedKeySet()method. From theSelectionKey.

當(dāng)你調(diào)用channel的register的方法的時(shí)候,會(huì)返回一個(gè)SelectionKey。這個(gè)代表channel和selector的關(guān)系

remove方法是必須要調(diào)用的,當(dāng)你處理好channel。通過SelectionKey.channel()會(huì)獲得channel對(duì)象,你可以類型轉(zhuǎn)換你要的Channel對(duì)象,比如ServerSocketChannel等


wakeUp()

一個(gè)線程調(diào)用select()就會(huì)阻塞,但是也可以脫離select()方法回到非阻塞狀態(tài),即使沒有channel轉(zhuǎn)備好。這種方式就是讓其他線程調(diào)用那個(gè)selector的wakeup()方法,然后select()方法會(huì)立即返回。

如果另外一個(gè)線程調(diào)用這個(gè)selector的wakeup方法,并且原來調(diào)用selector的select()方法的線程并沒有阻塞,那么下一個(gè)調(diào)用selector的select()方法會(huì)立即返回。

close()

與注冊(cè)相反,這個(gè)方法會(huì)使所有的selectKey無效

完整的栗子


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,694評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,672評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,690評(píng)論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,019評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評(píng)論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,188評(píng)論 0 290
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,718評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,438評(píng)論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,667評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,845評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評(píng)論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,384評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,635評(píng)論 2 380

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