netty源码阅读之NioEventLoop之NioEventLoop启动

触发NioEventLoop启动有两个方式:

1、服务端启动绑定端口

2、新连接接入通过chooser绑定一个NioEventLoop

在这里,我们先讲解第一种方式,后续文章讲解第二种。

NioEventLoop第一种启动方式入口从用户代码bind()进入,initAndRegister()方法的后面,有一个doBind0(),进入,便看到,channel绑定的NioEventLoop的execute方法:

channel.eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                if (regFuture.isSuccess()) {
                    channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                } else {
                    promise.setFailure(regFuture.cause());
                }
            }
        });

execute()做了添加线程和添加任务的事情,在添加线程里面,执行的是之前传进来的ThreadPerTaskExecutor的excute方法,这个方法实际上就是创建线程,绑定线程,执行线程:

1、thread=Thread.currentThread()

2、NioEventLoop.run()

第二个步骤下一篇文章详细讲解。现在来一步步分析:

NioEventLoop的execute方法这里:

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

        boolean inEventLoop = inEventLoop();
        if (inEventLoop) {
            addTask(task);
        } else {
            startThread();
            addTask(task);
            if (isShutdown() && removeTask(task)) {
                reject();
            }
        }

        if (!addTaskWakesUp && wakesUpForTask(task)) {
            wakeup(inEventLoop);
        }
    }

inEventLoop判断给我任务的线程是不是NioEventLoop的线程,如果不是就需要调用startThread()启动线程并且绑定到NioEventLoop上面,然后把任务丢到任务队列里面;否则,直接把这个任务添加到任务队列里面(这个队列就是上一篇的MpscQueue)。在这里,给任务的线程是主线程,并且NioEventLoop的线程也没有启动,所以调用startThread()方法.

startThread()一直进入,有个doStartThread方法:

    private void doStartThread() {
        assert thread == null;
        executor.execute(new Runnable() {
            @Override
            public void run() {
                thread = Thread.currentThread();
                ...
                try {
                    SingleThreadEventExecutor.this.run();
                    success = true;
                } catch (Throwable t) {
                    logger.warn("Unexpected exception from an event executor: ", t);
                } finally {
                    ...
                }
            }
        });
    }

这里就是调用ThreadPerTaskExecutor的execute方法,把新建的线程绑定到NioEventLoop的thread对象里面。然后有个

SingleThreadEventExecutor.this.run()方法,真正的去执行NioEventLoop的任务。

至于启动线程之后的addTask()方法,其实很简单,就是把任务加入到我们之前创建的newMpscQueue队列里面:

    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);
    }

猜你喜欢

转载自blog.csdn.net/fst438060684/article/details/81557852