深入了解java NIO之Selector(選擇器)
這一節(jié)我們將探索選擇器(selectors)。選擇器提供選擇執(zhí)行已經(jīng)就緒的任務(wù)的能力,這使得多元 I/O 成為可能。就像在第一章中描述的那樣,就緒選擇和多元執(zhí)行使得單線程能夠有效率地同時(shí)管理多個(gè) I/O 通道(channels)。C/C++代碼的工具箱中,許多年前就已經(jīng)有 select()和 poll()這兩個(gè)POSIX(可移植性操作系統(tǒng)接口)系統(tǒng)調(diào)用可供使用了。許過(guò)操作系統(tǒng)也提供相似的功能,但對(duì)Java 程序員來(lái)說(shuō),就緒選擇功能直到 JDK 1.4 才成為可行的方案。
下面我們來(lái)使用選擇器:
通過(guò) Selector.open()方法, 我們可以創(chuàng)建一個(gè)選擇器:
Selector selector = Selector.open();
將 Channel 注冊(cè)到選擇器中:
channel.configureBlocking(false); SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
注意, 如果一個(gè) Channel 要注冊(cè)到 Selector 中, 那么這個(gè) Channel 必須是非阻塞的, 即channel.configureBlocking(false);因?yàn)?Channel 必須要是非阻塞的, 因此 FileChannel 不能夠使用選擇器, 因?yàn)?FileChannel 都是阻塞的.
注意到, 在使用 Channel.register()方法時(shí), 第二個(gè)參數(shù)指定了我們對(duì) Channel 的什么類型的事件感興趣, 這些事件有:
- Connect, 即連接事件(TCP 連接), 對(duì)應(yīng)于SelectionKey.OP_CONNECT
- Accept, 即確認(rèn)事件, 對(duì)應(yīng)于SelectionKey.OP_ACCEPT
- Read, 即讀事件, 對(duì)應(yīng)于SelectionKey.OP_READ, 表示 buffer 可讀.
- Write, 即寫事件, 對(duì)應(yīng)于SelectionKey.OP_WRITE, 表示 buffer 可寫.
一個(gè) Channel發(fā)出一個(gè)事件也可以稱為 對(duì)于某個(gè)事件, Channel 準(zhǔn)備好了. 因此一個(gè) Channel 成功連接到了另一個(gè)服務(wù)器也可以被稱為 connect ready.
我們可以使用或運(yùn)算|來(lái)組合多個(gè)事件, 例如:
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
注意, 一個(gè) Channel 僅僅可以被注冊(cè)到一個(gè) Selector 一次, 如果將 Channel 注冊(cè)到 Selector 多次, 那么其實(shí)就是相當(dāng)于更新 SelectionKey 的 interest set. 例如:
channel.register(selector, SelectionKey.OP_READ); channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
上面的 channel 注冊(cè)到同一個(gè) Selector 兩次了, 那么第二次的注冊(cè)其實(shí)就是相當(dāng)于更新這個(gè) Channel 的 interest set 為 SelectionKey.OP_READ | SelectionKey.OP_WRITE.
但是Java NIO的selector允許一個(gè)單一線程監(jiān)聽多個(gè)channel輸入。我們可以注冊(cè)多個(gè)channel到selector上,然后然后用一個(gè)線程來(lái)挑出一個(gè)處于可讀或者可寫狀態(tài)的channel。selector機(jī)制使得單線程管理多個(gè)channel變得容易。
下面我們寫一個(gè)完整的例子,看一下Selector的用法:
//創(chuàng)建選擇器 Selector selector = Selector.open(); channel.configureBlocking(false); //注冊(cè)通道 SelectionKey key = channel.register(selector, SelectionKey.OP_READ); while(true) { //查看selector中的key是否準(zhǔn)備好 int readyChannels = selector.select(); //小于0超時(shí),等于0沒(méi)準(zhǔn)備好,大于0已經(jīng)準(zhǔn)備完畢 if(readyChannels == 0) continue; //獲取選擇器中的key Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while(keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); //遍歷已選擇鍵集中的每個(gè)鍵,并檢測(cè)各個(gè)鍵所對(duì)應(yīng)的通道的就緒事件 if(key.isAcceptable()) { // 連接已經(jīng)被ServerSocketChannel所接受 } else if (key.isConnectable()) { // 連接已經(jīng)被遠(yuǎn)程終止. } else if (key.isReadable()) { // 通道已經(jīng)準(zhǔn)備好讀數(shù)據(jù) } else if (key.isWritable()) { // 通道已經(jīng)準(zhǔn)備好寫數(shù)據(jù) } keyIterator.remove(); } }
選擇器的使用還有很多的細(xì)節(jié),我們應(yīng)該多查看api文檔了解各個(gè)方法的用法。下一節(jié)我們做一個(gè)綜合練習(xí),總結(jié)一下NIO的使用。
以上就是深入了解java NIO之Selector(選擇器)的詳細(xì)內(nèi)容,更多關(guān)于java nio Selector(選擇器)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
如何使用Comparator比較接口實(shí)現(xiàn)ArrayList集合排序
這篇文章主要介紹了如何使用Comparator比較接口實(shí)現(xiàn)ArrayList集合排序問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12解決Spring Security的權(quán)限配置不生效問(wèn)題
這篇文章主要介紹了解決Spring Security的權(quán)限配置不生效問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03Java開發(fā)學(xué)習(xí)之Bean的作用域和生命周期詳解
這篇文章主要介紹了淺談Spring中Bean的作用域,生命周期和注解,從創(chuàng)建到消亡的完整過(guò)程,例如人從出生到死亡的整個(gè)過(guò)程就是一個(gè)生命周期。本文將通過(guò)示例為大家詳細(xì)講講,感興趣的可以學(xué)習(xí)一下2022-06-06SpringBoot+ECharts是如何實(shí)現(xiàn)數(shù)據(jù)可視化的
今天帶大家學(xué)習(xí)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著SpringBoot+ECharts怎么實(shí)現(xiàn)數(shù)據(jù)可視化展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06SpringBoot 整合 Lettuce Redis的實(shí)現(xiàn)方法
這篇文章主要介紹了SpringBoot 整合 Lettuce Redis的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07SpringBoot實(shí)現(xiàn)郵件推送的詳細(xì)代碼
在項(xiàng)目中經(jīng)常會(huì)遇到SpringBoot推送消息的業(yè)務(wù),除了站內(nèi)推送通知,郵件推送也是一種常見(jiàn)的方式,本文小編就帶大家實(shí)現(xiàn)郵件推送,文中有詳細(xì)代碼講解,對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-04-04