netty源码阅读之NioEventLoop之NioEventLoop启动

本文解析了NioEventLoop的两种启动方式之一——服务端启动绑定端口的过程。介绍了如何通过bind()方法触发NioEventLoop的启动,并深入探讨了execute()方法的工作原理及线程绑定流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

触发NioEventLoop启动有两个方式:

1、服务端启动绑定端口

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

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

 

NioEventLoop第一种启动方式入口从用户代码bind()进入,initAndRegister()方法的后面,有一个doBind0(),进入,便看到,channel绑定的NioEventLoop的execute方法(这个NioEventLoop呢,其实是在前面端启动的时候initAndRegister的时候把NioEventLoop绑定进去的),也就是说,绑定是在nioEventLoop里面完成的:

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()(通过调用线程执行器来创建,创建的线程就是FastThreadLocalThread)启动线程并且绑定到NioEventLoop上面,然后把任务丢到NioEventLoop的任务队列里面(保证了线程安全);否则,直接把这个任务添加到任务队列里面(这个队列就是上一篇的MpscQueue,以后由NioEventLoop的线程去执行)。在这里,给任务的线程是主线程,并且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方法(这个ThreadPerTaskExecutor就是前面newChild创建NioEventLoop传进去的第一个参数),把新建的线程绑定到NioEventLoop的thread对象里面。然后有个SingleThreadEventExecutor.this.run()方法,真正的去执行NioEventLoop的任务。

ThreadPerTaskExecutor每次执行execute都会创建一个线程,这个线程的具体执行逻辑就是把当前的Thread绑定到NioEventLoop那里,然后调用SingleThreadEventExecutor.this.run()也就是NioEventLoop的run方法具体去执行任务。(这个run方法的内容,我们后面的文章重点分析)

至于启动线程之后的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);
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值