Netty源碼分析-NioEventLoop(二)

NioEventLoop源碼分析。

EventLoop的本質:內部一個線程,一個有序隊列存儲,線程源源不斷的運行隊列中的任務。

 

register方法把java-nio的channel註冊到selector上面。

    //把JAVA底層Channel註冊到selector上
    public void register(final SelectableChannel ch, final int interestOps, final NioTask<?> task) {
        //把ch註冊到java底層selector上面,代碼省略了一些安全檢查
        try {
            ch.register(selector, interestOps, task);
        } catch (Exception e) {
            throw new EventLoopException("failed to register a channel", e);
        }
    }

 

run方法是核心的啓動方法,在父類中,創建好線程啓動以後會調用run方法,在這裏會處理selector的selelct事件和所有的IO事件

 @Override
    protected void run() {
        //這個方法是父類定義的抽象方法,在父類線程創建啓動後調用此方法。
        for (;;) {
            try {
                        //如果底層隊列存儲在任務hasTasks會返回true,那麼調用selelctNow返回key的數量,可能爲0
                        //如果沒有則返回SelectStrategy.SELECT
                switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
                    case SelectStrategy.CONTINUE:
                        continue;
                    case SelectStrategy.SELECT:

                        //查詢selector,如果沒有任務則會在selector上阻塞一會,否則立即返回
                        select(wakenUp.getAndSet(false));

                        if (wakenUp.get()) {
                            selector.wakeup();
                        }
                        // fall through
                    default:
                }

                cancelledKeys = 0;
                needsToSelectAgain = false;
                //IO時間的比例
                final int ioRatio = this.ioRatio;
                //如果是百分百
                if (ioRatio == 100) {
                    try {
                        //先處理所有key事件
                        processSelectedKeys();
                    } finally {
                        // Ensure we always run tasks.
                        //然後處理所有IO任務
                        runAllTasks();
                    }
                } else {
                    final long ioStartTime = System.nanoTime();
                    try {
                        //先處理所有key事件
                        processSelectedKeys();
                    } finally {
                        // Ensure we always run tasks.
                        //執行一段時間的IO任務
                        final long ioTime = System.nanoTime() - ioStartTime;
                        runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
                    }
                }
            } catch (Throwable t) {
                handleLoopException(t);
            }
            // Always handle shutdown even if the loop processing threw an exception.
            try {
                if (isShuttingDown()) {
                    closeAll();
                    if (confirmShutdown()) {
                        return;
                    }
                }
            } catch (Throwable t) {
                handleLoopException(t);
            }
        }
    }

 

processSelectedKey,處理selector的selelct到的key。

 private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
        final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
        if (!k.isValid()) { //key無效
            final EventLoop eventLoop;
            try {
                eventLoop = ch.eventLoop();
            } catch (Throwable ignored) {
                // If the channel implementation throws an exception because there is no event loop, we ignore this
                // because we are only trying to determine if ch is registered to this event loop and thus has authority
                // to close ch.
                return;
            }
            
            //如果ch當中的el不是當前對象則return
            if (eventLoop != this || eventLoop == null) {
                return;
            }

            unsafe.close(unsafe.voidPromise());
            return;
        }

        try {
            //獲取key的事件類型
            int readyOps = k.readyOps();
            // We first need to call finishConnect() before try to trigger a read(...) or write(...) as otherwise
            // the NIO JDK channel implementation may throw a NotYetConnectedException.
            //如果是連接事件
            if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
                // remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
                // See https://github.com/netty/netty/issues/924
                int ops = k.interestOps();
                ops &= ~SelectionKey.OP_CONNECT;
                k.interestOps(ops);
                //完成連接
                unsafe.finishConnect();
            }

            //如果是write事件,則調用底層代碼寫入邏輯
            // Process OP_WRITE first as we may be able to write some queued buffers and so free memory.
            if ((readyOps & SelectionKey.OP_WRITE) != 0) {
                // Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
                ch.unsafe().forceFlush();
            }

            // Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead
            // to a spin loop
            //如果是讀事件,交給底層邏輯處理
            if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
                unsafe.read();
            }
        } catch (CancelledKeyException ignored) {
            unsafe.close(unsafe.voidPromise());
        }
    }

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章