溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

java中NIO之Selector是什么

發(fā)布時(shí)間:2020-07-02 14:40:04 來(lái)源:億速云 閱讀:128 作者:清晨 欄目:開(kāi)發(fā)技術(shù)

小編給大家分享一下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, 即寫(xiě)事件, 對(duì)應(yīng)于SelectionKey.OP_WRITE, 表示 buffer 可寫(xiě).
     

一個(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)聽(tīng)多個(gè)channel輸入。我們可以注冊(cè)多個(gè)channel到selector上,然后然后用一個(gè)線程來(lái)挑出一個(gè)處于可讀或者可寫(xiě)狀態(tài)的channel。selector機(jī)制使得單線程管理多個(gè)channel變得容易。

下面我們寫(xiě)一個(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)備好寫(xiě)數(shù)據(jù)
    }
    keyIterator.remove();
  }
}

看完了這篇文章,相信你對(duì)java中NIO之Selector是什么有了一定的了解,想了解更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI