我们在调用EventLoop.execute()方法时究竟做了一些什么工作

我们在研究注册过程中的源码可以看到这样的一段代码

                    eventLoop.execute(new Runnable() {
                        @Override
                        public void run() {
                            register0(promise);
                        }
                    });

那么这个execute方法里面的流程究竟是什么样的?因为NioEventLoop本身继承了SingleThreadEventExecutor,所以本身会调用父类的execute方法:

    @Override
    public void execute(Runnable task) {
        if (task == null) {
            throw new NullPointerException("task");
        }

        boolean inEventLoop = inEventLoop();//判断eventLoop中的线程是否已经启动
        if (inEventLoop) {
            addTask(task);//如果是,则添加任务
        } else {
            startThread();//如果不是,则启动线程
            addTask(task);//然后添加任务
            if (isShutdown() && removeTask(task)) {
                reject();
            }
        }

        if (!addTaskWakesUp && wakesUpForTask(task)) {
            wakeup(inEventLoop);
        }
    }
所以eventLoop的execute方法只会讲Runnable对象作为任务,添加的某个任务列表中。

在启动线程的方法中,跟踪,会有这样的代码

    private void doStartThread() {
        assert thread == null;
        executor.execute(new Runnable() {//值得注意的是这个executor的类是我们初始化eventloopgroup时分配好的一个ThreadPerTaskExecutor
            //实例,里面有一个线程工厂的实例,用于创建新的线程来执行传入的Runnable任务。
            @Override
            public void run() {
                thread = Thread.currentThread();//这里就对eventloop中的thread进行赋值,以后对eventLoop的excute调用将可能会返回true.
                if (interrupted) {
                    thread.interrupt();
                }

                boolean success = false;
                updateLastExecutionTime();
                try {
                    SingleThreadEventExecutor.this.run();//调用eventLoop的run方法,进行循环。
                    success = true;
                } catch (Throwable t) {

所以这个地方会立马新建并启动一个线程,执行Runnable.

跟踪到run方法中,里面会是一个死循环,我们挑出关键代码

    protected void run() {
        for (;;) {
            try {
                switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {//计算出选择策略,可以得出是select
                    case SelectStrategy.CONTINUE:
                        continue;
                    case SelectStrategy.SELECT:
                        select(wakenUp.getAndSet(false));//这里就是NIO中的selector.select(),然后将selectedKey赋予

                if (ioRatio == 100) {//默认值为50
                    try {
                        processSelectedKeys();
                    } finally {
                        // Ensure we always run tasks.
                        runAllTasks();
                    }
                } else {
                    final long ioStartTime = System.nanoTime();
                    try {
                        processSelectedKeys();//处理selectedKeys,,很激动,不就是Nio中对于Selector.selectedKeys的处理嘛。。。
                    } finally {
                        // Ensure we always run tasks.
                        final long ioTime = System.nanoTime() - ioStartTime;
                        runAllTasks(ioTime * (100 - ioRatio) / ioRatio);//执行添加到任务列表中的任务
                    }
                }

看一下processSelectedKeys的代码

    private void processSelectedKeys() {
        if (selectedKeys != null) {//这个是初始化形成的,是一个1024个selectKey的数组,所以判定不为空,但是里面没有值,所以size=0
            processSelectedKeysOptimized();
        } else {
            processSelectedKeysPlain(selector.selectedKeys());
        }
    }

    private void processSelectedKeysOptimized() {
        for (int i = 0; i < selectedKeys.size; ++i) {//刚开始会直接返回,因为size=0
            final SelectionKey k = selectedKeys.keys[i];
            // null out entry in the array to allow to have it GC'ed once the Channel close
            // See https://github.com/netty/netty/issues/2363
            selectedKeys.keys[i] = null;

            final Object a = k.attachment();

            if (a instanceof AbstractNioChannel) {
                processSelectedKey(k, (AbstractNioChannel) a);
            } else {
                @SuppressWarnings("unchecked")
                NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;
                processSelectedKey(k, task);
            }

            if (needsToSelectAgain) {
                // null out entries in the array to allow to have it GC'ed once the Channel close
                // See https://github.com/netty/netty/issues/2363
                selectedKeys.reset(i + 1);

                selectAgain();
                i = -1;
            }
        }
    }

随后就是执行任务,这样就死循环就会一直在这个线程中执行。

我们回到添加任务的方法那,从最开始,我们知道我们添加的是一个执行注册方法的任务

    protected void addTask(Runnable task) {
        if (task == null) {
            throw new NullPointerException("task");
        }
        if (!offerTask(task)) {
            reject(task);
        }
    }

    final boolean offerTask(Runnable task) {
        if (isShutdown()) {
            reject();
        }
        return taskQueue.offer(task);//所以,可以看出是添加到一个taskQueue中。Queue<Runnable> taskQueue
    }

而我们在那个线程中的死循环中是不断的执行所有的任务的,

 runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
    protected boolean runAllTasks() {
        assert inEventLoop();
        boolean fetchedAll;
        boolean ranAtLeastOne = false;

        do {
            fetchedAll = fetchFromScheduledTaskQueue();
            if (runAllTasksFrom(taskQueue)) {
                ranAtLeastOne = true;
            }
        } while (!fetchedAll); // keep on processing until we fetched all scheduled tasks.

        if (ranAtLeastOne) {
            lastExecutionTime = ScheduledFutureTask.nanoTime();
        }
        afterRunningAllTasks();
        return ranAtLeastOne;
    }

所以到在采取运行注册的任务

selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);

我们在执行完register0()里的doRegister()之后

        private void register0(ChannelPromise promise) {
            try {
                // check if the channel is still open as it could be closed in the mean time when the register
                // call was outside of the eventLoop
                if (!promise.setUncancellable() || !ensureOpen(promise)) {
                    return;
                }
                boolean firstRegistration = neverRegistered;
                doRegister();//执行具体的注册流程
                neverRegistered = false;
                registered = true;

                // Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
                // user may already fire events through the pipeline in the ChannelFutureListener.
                pipeline.invokeHandlerAddedIfNeeded();//我们会调用之前addLast挂起的一些任务,最终完成channelHandler的添加,
                //传播添加handler成功的事件

                safeSetSuccess(promise);
                pipeline.fireChannelRegistered();//传播注册完成事件
                // Only fire a channelActive if the channel has never been registered. This prevents firing
                // multiple channel actives if the channel is deregistered and re-registered.
                if (isActive()) {
                    if (firstRegistration) {
                        pipeline.fireChannelActive();
                    } else if (config().isAutoRead()) {
                        // This channel was registered before and autoRead() is set. This means we need to begin read
                        // again so that we process inbound data.
                        //
                        // See https://github.com/netty/netty/issues/4805
                        beginRead();
                    }
                }
            } catch (Throwable t) {
                // Close the channel directly to avoid FD leak.
                closeForcibly();
                closeFuture.setClosed();
                safeSetFailure(promise, t);
            }
        }


猜你喜欢

转载自blog.csdn.net/u013828625/article/details/79818571