jdk的Selector源碼分析(一)Selector概述

1系列內容

2 jdk Selector概述

首先來看下文檔描述linux

2.1 建立方式

一個就是直接調用open方法windows

public static Selector open() throws IOException {
    return SelectorProvider.provider().openSelector();
}

或者調用選用某個SelectorProvider的openSelector安全

public abstract AbstractSelector openSelector()

2.2 SelectionKey

一個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。

2.3 三種select方式

分別以下:

int select():表示一直阻塞到有事件爲止

int select(long timeout):最多阻塞timeout時間

int selectNow():不阻塞,檢查結果後當即返回

2.4 併發性

Selector不是線程安全的,不過大部分狀況都是一個線程擁有一個Selector,因此不須要它線程安全。

2.5 使用案例

以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集合。而後遍歷該集合,執行對應的事件。

3 不一樣實現類

目前Selector目前有以下實現

Selector實現類

針對linux平臺的實現:

  • PollSelectorImpl:基於poll來實現
  • EPollSelectorImpl:基於epoll來實現

針對windows平臺的實現:

  • WindowsSelectorImpl

而Netty的NioEventLoop則是使用上述linux平臺的實現PollSelectorImpl。Netty本身提供了另一種epoll實現,沒有直接採用上述jdk自帶的EPollSelectorImpl。

4 後續

接下來就要開始重點說說jdk的poll是怎麼實現的,即PollSelectorImpl的內容

相關文章
相關標籤/搜索