首先來看下文檔描述linux
一個就是直接調用open方法windows
public static Selector open() throws IOException { return SelectorProvider.provider().openSelector(); }
或者調用選用某個SelectorProvider的openSelector安全
public abstract AbstractSelector openSelector()
一個Selector有3種SelectionKey集合併發
一種就是所有註冊的SelectionKey集合,即keys()方法返回的結果socket
一種就是活躍的SelectionKey集合,即selectedKeys()方法返回的結果ide
第三種就是已取消的SelectionKey集合,這些已被取消可是還未從Selector取消註冊oop
再確認下下面的幾個問題:.net
什麼叫註冊線程
即將一個channel感興趣的事件註冊到Selector上,即以下方法設計
SelectionKey register(AbstractSelectableChannel ch, int ops, Object att)
對於select、poll的Selector實現:僅僅是保存上述AbstractSelectableChannel感興趣的ops到指定地方
對於epoll的Selector實現:則是執行系統調用epoll_ctl方法,操做參數是EPOLL_CTL_ADD
什麼叫取消
就是調用SelectionKey的cancel方法,該方法的實現是,將該SelectionKey放入cancelledKeys而已,沒有作其餘操做
什麼叫取消註冊
取消註冊,就是從Selector從釋放出來再也不關注某個事件。一般在咱們的select過程當中就會遍歷上述cancelledKeys,依次執行取消註冊的行爲。不一樣的Selector有不一樣的行爲,如epoll則是執行系統調用epoll_ctl方法,操做參數是EPOLL_CTL_DEL。
分別以下:
int select():表示一直阻塞到有事件爲止 int select(long timeout):最多阻塞timeout時間 int selectNow():不阻塞,檢查結果後當即返回
Selector不是線程安全的,不過大部分狀況都是一個線程擁有一個Selector,因此不須要它線程安全。
以ZooKeeper爲例,代碼簡述以下
final Selector selector = Selector.open(); public void run() { while (!ss.socket().isClosed()) { try { selector.select(1000); Set<SelectionKey> selected = selector.selectedKeys(); for (SelectionKey k : selected) { if ((k.readyOps() & SelectionKey.OP_ACCEPT) != 0) { //執行accept鏈接的事件 SocketChannel sc = ((ServerSocketChannel) k .channel()).accept(); sc.configureBlocking(false); SelectionKey sk = sc.register(selector, SelectionKey.OP_READ); NIOServerCnxn cnxn = createConnection(sc, sk); sk.attach(cnxn); addCnxn(cnxn); } else if ((k.readyOps() & (SelectionKey.OP_READ | SelectionKey.OP_WRITE)) != 0) { //執行IO讀寫事件 NIOServerCnxn c = (NIOServerCnxn) k.attachment(); c.doIO(k); } else { //未知 } } selected.clear(); } catch (RuntimeException e) { LOG.warn("Ignoring unexpected runtime exception", e); } catch (Exception e) { LOG.warn("Ignoring exception", e); } } closeAll(); LOG.info("NIOServerCnxn factory exited run method"); }
while循環裏面不斷調用selector.select(1000)方法,而後經過selector.selectedKeys()來獲取到有事件的SelectionKey集合,即上述提到的活躍的SelectionKey集合。而後遍歷該集合,執行對應的事件。
目前Selector目前有以下實現
針對linux平臺的實現:
針對windows平臺的實現:
而Netty的NioEventLoop則是使用上述linux平臺的實現PollSelectorImpl。Netty本身提供了另一種epoll實現,沒有直接採用上述jdk自帶的EPollSelectorImpl。
接下來就要開始重點說說jdk的poll是怎麼實現的,即PollSelectorImpl的內容