NIO之坑:徹底理解NIO Selector

Selector是什麼


如何建立一個Selector對象


如何將selectable channel註冊到selector中

SelectionKey key = channel.register(selector,Selectionkey.XXX); 
複製代碼
  • 經過channelregister方法,將channel註冊到給定的selector中,並返回一個表示註冊關係的SelectionKey 對象。

selector如何維護selection keys

  • 一個selector維護着三個selection keys集合:html

    • key set 包含着全部selectionKeys,當前全部註冊到selector中的channel返回的註冊關係SelectionKey都包含在內,這個集合能夠經過selector.keys() 方法返回。java

    • selected-key set 包含着一部分selectionKeys,其中的每一個selectionKey所關聯的channelselection operation期間被檢測出至少 準備好 了一個能夠在興趣集中匹配到的操做。這個集合能夠經過調用selector.selectedKeys()方法返回。selected-key set 必定是 key set 的子集。api

    • cancelled-key set 也包含着一部分selectionKeys,其中的每一個selectionKey都已經被取消,可是所關聯channel尚未被撤銷登記cancelled-key set 不可以被直接返回,但也必定是 key set 的子集。安全

    對於一個新建立的selector其中這三個集合都是空着的。多線程

    經過channelregister方法,一個selectionKey被增長到selectorkey set 中。併發

    不管經過channel.close()仍是經過selectionKey.cancel()取消一個selectionKey ,這個selectionKey都會被當即添加到selectorcancelled-key set 中,可是所關聯的channel並無當即被撤銷登記,直到發生下次 selection operations, 這些channel才被從selector撤銷登記,與此同時這些Cancelled keys纔會被從這個selector的全部selectionKey set(多是_key set_、selected-key setcancelled-key set)中移除,可是不會影響這些集合自己。oracle

    selection operations 期間,一些selectionKey會被選中添加到 selected-key set 中。其中的每一個key能夠經過selectiedKeys.remove()selectiedKeys.iterator().remove()直接從 selected-key set 中移除,除此以外不可以經過任何方式被直接移除。特殊的,selected-key set 中的keys還能夠在 selection operations 期間被間接移除。可是是不能夠直接向 selected-key set 添加key的。ide


selector如何選擇就緒channel

  • 每次 selection operation 期間, keys均可以從selector's selected-key set 被添加或者移除,同時也能夠從它的 keycancelled-key sets 被移除。 selection operation 能夠被觸發經過執行selector.select()selector.select(long),和selector.selectNow() 方法,而且這些方法涉及到如下三個步驟:
  1. 首先每一個位於 cancelled-key set 中的key會從每一個包含它的key集合中被移除,而且對應的channel會被撤銷登記。這個步驟使得 cancelled-key set 變爲空。spa

  2. 查詢底層操做系統來得到關於selector中剩餘channel就續事件selection operation 開始截止到此刻的更新狀況,只要哪一個channel就續事件的更新部分有至少一個與興趣集中的操做匹配上,那麼將會執行如下兩個動做:操作系統

    1. 若是這個channel's key 沒有存在selected-key set 那麼將它添加到這個集合中,並將它的就緒操做集(ready-operation set)修改爲 只包含使得channel被報告就緒的操做,任何先前記錄在就緒操做集中的就緒信息都會被丟棄。

    2. 不然,若是這個channel's key 存在selected-key set ,那麼就保留就緒操做集中先前的就緒信息,並將這些 使得channel被報告就緒的操做 寫入進去;總而言之,系統底層會經過按位與&操做更新當前就緒集。

    若是這些Key興趣集爲空,那麼 selected-key set 和 keys'的就續集(ready-operation sets)都不會被更新。

  3. 若是在步驟(2)正在進行時將任何key添加到 cancelled-key set,則按步驟(1)處理它們。

  • selection operations 是否會阻塞等待一個或多個通道準備就緒,以及等待多長時間,這是三種選擇方法之間惟一的本質區別。

selector線程安全嗎

多線程併發狀況下Selectors自己是線程安全的,可是他們所持有的key sets不是線程安全的。

selection operations 按順序在selector自己,key setselected-key set 上同步。 它們還在上面的步驟(1)和(3)期間在 canceled-key set 上同步。

selection operations 期間改變key興趣集,對於本次操做將不會產生任何影響;它們的影響將會再下次 selection operations 期間發生。

selectionKey可能會被取消,channel可能隨時關閉。 所以,在一個或多個選擇器的key集中存在並不意味着selectionKey有效或其channel是開放的。有可能另外一個線程取消selectionKey或關閉一個channel,應用程序代碼應該當心地同步並檢查這些條件。

一個線程經過selector.select()selector.select(long)方法產生的阻塞能夠被其餘線程用如下三種方式的任意一種來中斷:

  • By invoking the selector's wakeup() method,

  • By invoking the selector's close() method, or

  • By invoking the blocked thread's interrupt() method, in which case its interrupt status will be set and the selector's wakeup() method will be invoked.

selector.close()selection operations 期間會順序的同步selectorand all three key sets

一個selectorkey setselected-key set 一般狀況下是線程不安全的。若是一個線程想要修改這個集合,須要同步控制它。經過key集合iterator()方法返回的Iterators提供了快速失敗fail-fast):若是在建立迭代器以後修改了set,除了經過調用迭代器本身的remove() 方法以外,將拋出ConcurrentModificationException

相關文章
相關標籤/搜索