JAVA NIO 翻譯系列(六、Selector)

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


為什么使用selector?

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

但請(qǐng)記住,現(xiàn)代的操作系統(tǒng)和cpu在多任務(wù)處理上正變的越來(lái)越好,多線程花費(fèi)的時(shí)間越來(lái)越少。實(shí)際上,如果一個(gè)cpu是多核的,你不做多任務(wù)處理的話,可能正是一種資源浪費(fèi)。總之,這塊屬于不同區(qū)域的討論。僅對(duì)此處而言,一個(gè)selector可以用一個(gè)縣城來(lái)處理多個(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通過(guò)selector對(duì)什么事件感興趣,有以下四個(gè)事件可以監(jiān)聽(tīng)到:

? ? ?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

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

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

Ready Set

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

int readySet = selectionKey.readyOps();

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

selectionKey.isAcceptable();

selectionKey.isConnectable();

selectionKey.isReadable();

selectionKey.isWritable();


Channel + Selector

你可以通過(guò)SelectionKey來(lái)訪問(wèn)Channel和Selector對(duì)象

Channel? channel? = selectionKey.channel();

Selector selector = selectionKey.selector();


Attaching Objects

你可以在selectionKey附加一個(gè)Object對(duì)象,來(lái)標(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í)候傳遞的。換句話說(shuō)如果你注冊(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)備好了,你可以通過(guò)selected key set去訪問(wèn)準(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。通過(guò)SelectionKey.channel()會(huì)獲得channel對(duì)象,你可以類(lèi)型轉(zhuǎn)換你要的Channel對(duì)象,比如ServerSocketChannel等


wakeUp()

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

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

close()

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

完整的栗子


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容