Netty源码深度解析-EventLoop(2)EventLoop的工作原理

导读

原创文章,转载请注明出处。

本文源码地址:netty-source-code-analysis

本文所使用的netty版本4.1.6.Final:带注释的netty源码

EventLoop在netty中发挥着驱动引擎的作用,本文我们以NioEventLoop为例分析一下EventLoop的工作原理。

1 EventLoop线程的创建时机

还记得我们在“服务端启动”和“客户端启动”这两篇文章中都有一个重要操作吗?就是将Channel注册到EventLoop上。我们看AbstractChannelregister方法,其中有eventLoop.execute调用,是不是很熟悉。大多数情况下(并非绝对),这里就是EventLoop线程开始的地方

public final void register(EventLoop eventLoop, final ChannelPromise promise) {
    if (eventLoop.inEventLoop()) {
        register0(promise);
    } else {
        try {
            eventLoop.execute(new Runnable() {
                @Override
                public void run() {
                    register0(promise);
                }
            });
        } catch (Throwable t) {

        }
    }
}

咱们跟进去execute方法,这个方法的实现在SingleThreadEventExecutor中,我们看到这里有一个startThread方法,看名字就知道,这里是线程真正开始的地方,一起来看看吧。

后面的!addTaskWakesUp && wakesUpForTask(task)是怎么回事呢?

EventLoop的实现中,有的EventLoop实现会阻塞在任务队列上,对于这样的EventLoop唤醒方法是向任务队列中添加一个比较特殊的任务,这样的EventLoopaddTaskWakesUpture

而有的EventLoop比如NioEventLoop不会阻塞在任务队列上,但是会阻塞在selector上,对于这样的EventLoop通过调用wakeup方法唤醒,这样的EventLoopaddTaskWakesUpfalse

 public void execute(Runnable task) {
   
        boolean inEventLoop = inEventLoop();
        if (inEventLoop) {
   
            addTask(task);
        } else {
   
            startThread();
            addTask(task);
            if (isShutdown() && removeTask(task)) {
   
                reject();
            }
        }
        
        if (!addTaskWakesUp && wakesUpForTask(task)) {
   
            wakeup(inEventLoop);
        }
    }

我们看看SingleThreadEventExecutor中的wakeup方法,这里通过向队列中添加一个特殊的task来唤醒EventLoop线程。

protected void wakeup(boolean inEventLoop) {
    if (!inEventLoop || STATE_UPDATER.get(this) == ST_SHUTTING_DOWN) {
        taskQueue.offer(WAKEUP_TASK);
    }
}

NioEventLoop中覆盖了这个wakeup方法,通过调用selector.wakeup方法来唤醒EventLoop线程,因为wakeup是个重量级操作,所以netty用了一个AtomicBoolean类型的wakenUp变量来减少wakeup的次数,如果已经被wakeup了,就不再调用selector.wakeup

protected void wakeup(boolean inEventLoop) {
    if (!inEventLoop && wakenUp.compareAndSet(false, true)) {
        selector.wakeup();
    }
}

startThread方法中首先对EventLoop的状态做了判断,如果为ST_NOT_STARTED(未开始)状态,才调用doStartThread方法,接着跟下去看doStartThread方法。

private void startThread() {
   
    if (STATE_UPDATER.get(this) == ST_NOT_STARTED) {
   
        if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
   
            doStartThread();
        }
    }
}

doStartThread接着调用了SingleThreadEventExecutor.this.run()方法,这个run方法是抽象的,在这里没有实现。我们重点关注NioEventLoop,所以我们去看NioEventLooprun方法的实现。

我们前面已经讲过了这个executorThreadPerTaskExecutor,所以这里调用execute方法会创建出一个新的线程,这个线程就是EventLoop线程。

private void doStartThread() {
   
    assert thread == null;
    executor.execute(new Runnable() {
   
        @Override
        public void run() {
   
            try {
   
       
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值