【Netty学习】EventLoop源码剖析

Netty的核心代码十分复杂,NioEventLoop是一个重量级类,我们没办法全部看一遍,这里我会选出核心的流程,带着问题去看源码,便会事半功倍,废话不多说,咱们开始

老规矩,先看看NioEventLoop的继承关系

在这里插入图片描述

NioEventLoop的设计原理

Netty的NioEventLoop并不是一个纯粹的I/O线程,它除了负责I/O的读写之外,还负责处理以下两种任务

  • 系统的task:也就是普通的task任务,通过调用NioEventLoo的execute(task)方法实现,Netty有许多系统Task,为了更好协调用户线程和IO线程
  • 定时任务:从继承关系中也看出,NioEventLoop实现了ScheduledExecutorService接口,所以可以调用NioEventLoop的schedule方法执行定时任务
  • 明白一点:NioEventLoop=Selector+thread+taskQueue
  • 底层使用单线程线程池执行任务和IO事件,熟悉线程池的应该明白,类似于线程池的SynchronousQueue阻塞队列

正式由于NioEventLoop具有多种职责,所以具体的实现源码十分复杂,接下来我们带着问题来看核心代码

1.selector是何时创建的,为什么会有两个selector成员变量

我们找到NioEventLoop的构造方法

NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
                 SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler,
                 EventLoopTaskQueueFactory queueFactory) {
   
        super(parent, executor, false, newTaskQueue(queueFactory), newTaskQueue(queueFactory),
                rejectedExecutionHandler);
        if (selectorProvider == null) {
   
            throw new NullPointerException("selectorProvider");
        }
        if (strategy == null) {
   
            throw new NullPointerException("selectStrategy");
        }
        provider = selectorProvider;
        // 核心在此,我们点进去openSelector()方法一探究竟
        final SelectorTuple selectorTuple = openSelector();
        selector = selectorTuple.selector;
        unwrappedSelector = selectorTuple.unwrappedSelector;
        selectStrategy = strategy;
    }

//openSelector()方法极其复杂,关于selector的初始化,核心在于此行代码
//可以看到openSelector()就是创建了一个selector对象
	unwrappedSelector = provider.openSelector();
//对比Nio中的Selector.open()方法可以看到,Netty使用的也是相同的方法创建selector对象
	SelectorProvider.provider().openSelector();

所以selector是在创建NioEventLoop对象调用构造方法时创建的

还有一个遗留问题,为什么有两个selector对象

在NioEventLoop中我们可以看到两个selector对象
在这里插入图片描述

  • unwrappedSelector是Nio底层提供的,selector是Netty为了提升性能对原始对象的包装
  • 我们通过selector.selectedKeys()来获取要监听的事件,Nio提供的是以set为容器的集合,但set涉及到散列表的遍历,为了追求效率,Netty包装了selector,用数组来作为容器,通过下标即可直接访问到对应的keys
  • 但一些方法还是需要用到原始的selector提供的方法,所以索性就把两个都留下来,当用到selectedKeys相关时就用Netty包装的selector类

2.NioEventLoop的线程何时启动

前文我们说过NioEventLoop=Selector+thread+taskQueue,那么thread是在何时启动的呢?

先说结论

thread是在第一次调用execute()方法时初始化创建,接下来我们进源码看看

//此方法继承于SingleThreadEventExecutor,所以这里的execute执行器只会支配一个thread工作线程,一个工作线程不断处理taskQueue任务和IO事件
@Override
    public void execute(Runnable task) {
   
        if (task == null) {
   
            throw new NullPointerException("task");
        }

        boolean inEventLoop = inEventLoop();//@1
        // 接下来会把task加入任务队列,此处和thread的初始化无关,咱不讨论
        
  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值