Netty源码分析篇:NioEventLoopGroup分析

Netty源码分析:NioEventLoopGroup Netty学习笔记:NioEventLoopGroup在工作之余,看到自己公司的超哥(俞超)关于Netty的系列博文,讲解的很好,因此,自己在学习之余也跟了下源代码,来了解Netty,也做了相关的笔记,将形成系列博文,这是第一篇。超哥的博文地址在这里:http://www.jianshu.com/p/c5068caab217Netty版本:4.0.23.Final借用超哥的例子,一般服务端的代码如下 阅读详情

NioEventLoopGroup 源码深度解析

一、什么是 NioEventLoopGroup?

在学习 Netty 的时候,我们经常会看到这样的代码:

EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();

那么 NioEventLoopGroup 到底是什么呢?

简单来说,NioEventLoopGroup 是 Netty 中的线程池实现。但它和我们熟悉的 ThreadPoolExecutor 不太一样,它是专门为事件驱动的 NIO 模型设计的线程池。

1.1 用一个比喻来理解

你可以把 NioEventLoopGroup 想象成一个餐厅的服务员团队:

  • NioEventLoopGroup = 整个服务员团队(线程池)
  • NioEventLoop = 每个服务员(单个线程)
  • Channel = 每张餐桌(客户端连接)

当有客户(客户端)来用餐时,餐厅经理(Chooser)会分配一个服务员(NioEventLoop)来负责这张桌子。这个服务员会一直服务这张桌子,直到客户离开。

1.2 NioEventLoopGroup 的核心特点

  1. 固定数量的线程:创建时就确定了有多少个 NioEventLoop(线程)
  2. 每个线程独立工作:每个 NioEventLoop 有自己的任务队列和 Selector
  3. 负载均衡:通过 Chooser 将新连接分配给不同的 NioEventLoop
  4. 线程绑定:一个 Channel 绑定到一个 NioEventLoop 后就不会改变

二、NioEventLoopGroup 的构造方法

打开 NioEventLoopGroup 的源码,可以看到它有多个构造方法。作为初学者,我们只需要关注最常用的几个:

2.1 常用的构造方法

// 1. 无参构造(最常用)
public NioEventLoopGroup() {
    this(0);  // 传入 0,会使用默认线程数
}

// 2. 指定线程数(推荐使用)
public NioEventLoopGroup(int nThreads) {
    this(nThreads, (Executor) null);
}

// 3. 指定线程数和 Executor(高级用法)
public NioEventLoopGroup(int nThreads, Executor executor) {
    this(nThreads, executor, SelectorProvider.provider());
}

// 4. 指定线程数、Executor 和 SelectorProvider(更高级)
public NioEventLoopGroup(int nThreads, Executor executor, 
                         final SelectorProvider selectorProvider) {
    this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}

// 5. 参数最全的构造方法(源码内部使用)
public NioEventLoopGroup(int nThreads, Executor executor, 
                         final SelectorProvider selectorProvider,
                         final SelectStrategyFactory selectStrategyFactory) {
    super(nThreads, executor, selectorProvider, selectStrategyFactory, 
          RejectedExecutionHandlers.reject());
}

2.2 构造参数详解

看到这么多参数,是不是有点懵?别担心,我们一个一个来理解:

参数名作用通俗解释
nThreads线程数量决定创建多少个 NioEventLoop(服务员数量)
Executor线程创建器注意:不是线程池!只是用来创建线程的工具
EventExecutorChooserFactory线程选择器工厂决定如何从线程池中选择一个线程(如何分配服务员)
SelectorProviderSelector 提供者为每个 NioEventLoop 创建 Selector(NIO 的核心组件)
SelectStrategy选择策略决定是阻塞等待还是立即返回
RejectedExecutionHandler拒绝策略当任务队列满了怎么办
children 数组核心数据结构存储所有 NioEventLoop 实例的数组

2.3 初学者应该怎么用?

对于初学者来说,记住这两种用法就够了:

// 方式1:使用默认线程数(CPU核心数 * 2)
NioEventLoopGroup group = new NioEventLoopGroup();

// 方式2:指定线程数(推荐)
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);      // Boss 只需要 1 个线程
NioEventLoopGroup workerGroup = new NioEventLoopGroup(4);    // Worker 可以多个线程

三、NioEventLoopGroup 的初始化过程

现在我们来看看,当你 new NioEventLoopGroup() 的时候,Netty 内部到底做了什么。

整个初始化过程可以分为 7 个步骤,我们一步一步来看:

步骤1:确定线程数量(nThreads)

// 在 MultithreadEventLoopGroup 中
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
    // 如果 nThreads 为 0,使用默认值
    super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}

// DEFAULT_EVENT_LOOP_THREADS 的计算逻辑
static {
    DEFAULT_EVENT_LOOP_THREADS = Math.max(1, 
        SystemPropertyUtil.getInt("io.netty.eventLoopThreads", 
        NettyRuntime.availableProcessors() * 2));
}

通俗解释:

  • 如果你传入 0 或者不传参数,Netty 会自动计算线程数
  • 默认线程数 = CPU 核心数 × 2
  • 比如你的电脑是 4 核 CPU,那么默认会创建 8 个线程
  • 你也可以通过系统属性 io.netty.eventLoopThreads 来指定

为什么是 CPU 核心数 × 2?

因为 NIO 是 IO 密集型操作,线程经常会阻塞在 IO 上,所以可以创建比 CPU 核心数更多的线程来提高吞吐量。

步骤2:创建线程创建器(Executor)

// 在 MultithreadEventExecutorGroup 中
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
    // 如果没有传入 executor,创建默认的 ThreadPerTaskExecutor
    this(nThreads, executor == null ? null : new ThreadPerTaskExecutor(executor), args);
}

// 如果 executor 为 null,会创建默认的
if (executor == null) {
    executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}

ThreadPerTaskExecutor 的实现:

public final class ThreadPerTaskExecutor implements Executor {
    private final ThreadFactory threadFactory;

    public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    @Override
    public void execute(Runnable command) {
        // 每次执行任务都创建一个新线程
        threadFactory.newThread(command).start();
    }
}

通俗解释:

  • Executor 不是线程池,它只是一个线程创建器
  • ThreadPerTaskExecutor 的作用是:每次需要线程时,就创建一个新线程
  • 这个 Executor 会为每个 NioEventLoop 创建一个专属的工作线程
  • 创建出来的线程名字类似:nioEventLoopGroup-2-1、nioEventLoopGroup-2-2 等

为什么不用线程池?

因为每个 NioEventLoop 只需要一个固定的线程,这个线程会一直运行,不需要复用。

步骤3:创建线程选择器(EventExecutorChooser)

// 在 MultithreadEventExecutorGroup 中
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
    this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
}

DefaultEventExecutorChooserFactory 的实现:

public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory {
    
    @Override
    public EventExecutorChooser newChooser(EventExecutor[] executors) {
        // 判断线程数是否是 2 的幂次方
        if (isPowerOfTwo(executors.length)) {
            // 如果是 2 的幂次方,使用位运算优化
            return new PowerOfTwoEventExecutorChooser(executors);
        } else {
            // 否则使用普通的取模运算
            return new GenericEventExecutorChooser(executors);
        }
    }
    
    private static boolean isPowerOfTwo(int val) {
        return (val & -val) == val;
    }
}

两种 Chooser 的实现:

// 1. 位运算优化版本(当线程数是 2 的幂次方时使用)
private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
    private final AtomicInteger idx = new AtomicInteger();
    private final EventExecutor[] executors;

    @Override
    public EventExecutor next() {
        // 使用位运算代替取模,性能更好
        return executors[idx.getAndIncrement() & executors.length - 1];
    }
}

// 2. 普通取模版本
private static final class GenericEventExecutorChooser implements EventExecutorChooser {
    private final AtomicInteger idx = new AtomicInteger();
    private final EventExecutor[] executors;

    @Override
    public EventExecutor next() {
        // 使用取模运算
        return executors[Math.abs(idx.getAndIncrement() % executors.length)];
    }
}

通俗解释:

  • Chooser 的作用是:从线程池中选择一个线程来处理新连接
  • 选择策略是轮询(Round-Robin):0 → 1 → 2 → 3 → 0 → 1 → …
  • 如果线程数是 2 的幂次方(2、4、8、16…),使用位运算优化,速度更快
  • 否则使用普通的取模运算

举个例子:

假设你创建了 4 个线程(2 的幂次方):

第 1 个连接 → idx=0 → 0 & 3 = 0 → 选择线程 0
第 2 个连接 → idx=1 → 1 & 3 = 1 → 选择线程 1
第 3 个连接 → idx=2 → 2 & 3 = 2 → 选择线程 2
第 4 个连接 → idx=3 → 3 & 3 = 3 → 选择线程 3
第 5 个连接 → idx=4 → 4 & 3 = 0 → 选择线程 0(循环)

步骤4:创建 Selector 提供者(SelectorProvider)

public NioEventLoopGroup(int nThreads, Executor executor) {
    // 使用系统默认的 SelectorProvider
    this(nThreads, executor, SelectorProvider.provider());
}

在 NioEventLoop 中的使用:

// 每个 NioEventLoop 创建时,会使用 SelectorProvider 创建自己的 Selector
Selector selector = selectorProvider.openSelector();

通俗解释:

  • SelectorProvider 是 Java NIO 提供的类,用于创建 Selector
  • 每个 NioEventLoop 都有自己独立的 Selector
  • Selector 是 NIO 的核心,用于监听多个 Channel 的 IO 事件
  • 通常我们使用系统默认的 SelectorProvider 就可以了

步骤5:创建选择策略(SelectStrategy)

public NioEventLoopGroup(int nThreads, Executor executor, 
                         final SelectorProvider selectorProvider) {
    this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}

DefaultSelectStrategyFactory 的实现:

final class DefaultSelectStrategyFactory implements SelectStrategyFactory {
    static final SelectStrategyFactory INSTANCE = new DefaultSelectStrategyFactory();

    @Override
    public SelectStrategy newSelectStrategy() {
        return DefaultSelectStrategy.INSTANCE;
    }
}

DefaultSelectStrategy 的实现:

final class DefaultSelectStrategy implements SelectStrategy {
    static final SelectStrategy INSTANCE = new DefaultSelectStrategy();

    @Override
    public int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception {
        // 如果有任务,执行非阻塞的 selectNow(),立即返回
        // 如果没有任务,返回 SELECT 标记,后续会执行阻塞的 select()
        return hasTasks ? selectSupplier.get() : SelectStrategy.SELECT;
    }
}

通俗解释:

  • SelectStrategy 决定了 NioEventLoop 的工作模式
  • 如果任务队列有任务:执行 selectNow()(非阻塞,立即返回)
  • 如果任务队列没有任务:执行 select()(阻塞等待 IO 事件)
  • 这样可以在处理 IO 事件和执行任务之间取得平衡

为什么要这样设计?

  • 如果一直阻塞在 select() 上,任务队列的任务就得不到及时处理
  • 如果一直执行 selectNow(),会浪费 CPU 资源
  • 所以根据是否有任务来动态选择,既能及时处理任务,又不会浪费 CPU

步骤6:创建拒绝策略(RejectedExecutionHandler)

public NioEventLoopGroup(int nThreads, Executor executor, 
                         final SelectorProvider selectorProvider,
                         final SelectStrategyFactory selectStrategyFactory) {
    super(nThreads, executor, selectorProvider, selectStrategyFactory, 
          RejectedExecutionHandlers.reject());  // 使用默认的拒绝策略
}

RejectedExecutionHandlers 的实现:

public final class RejectedExecutionHandlers {
    
    // 直接拒绝,抛出异常
    public static RejectedExecutionHandler reject() {
        return REJECT;
    }
    
    private static final RejectedExecutionHandler REJECT = new RejectedExecutionHandler() {
        @Override
        public void rejected(Runnable task, SingleThreadEventExecutor executor) {
            throw new RejectedExecutionException("Task " + task.toString() + 
                                                 " rejected from " + executor.toString());
        }
    };
}

通俗解释:

  • 每个 NioEventLoop 都有一个任务队列(默认容量是无限的)
  • 如果队列满了(或者 EventLoop 已经关闭),新任务会被拒绝
  • 默认的拒绝策略是:直接抛出 RejectedExecutionException 异常
  • 这和 ThreadPoolExecutor 的拒绝策略类似

步骤7:创建 children 数组并初始化(核心)

这是整个初始化过程中最核心的部分!所有参数设置完成后,会进入这个方法:

protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                        EventExecutorChooserFactory chooserFactory, 
                                        Object... args) {
    // ========== 1. 参数校验 ==========
    if (nThreads <= 0) {
        throw new IllegalArgumentException(
            String.format("nThreads: %d (expected: > 0)", nThreads));
    }

    // ========== 2. 创建默认的 Executor ==========
    if (executor == null) {
        executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
    }

    // ========== 3. 创建 children 数组(核心数据结构)==========
    children = new EventExecutor[nThreads];

    // ========== 4. 循环创建每一个 NioEventLoop 实例 ==========
    for (int i = 0; i < nThreads; i ++) {
        boolean success = false;
        try {
            // 调用 newChild() 方法创建 NioEventLoop
            // 这个方法在 NioEventLoopGroup 中被覆写
            children[i] = newChild(executor, args);
            success = true;
        } catch (Exception e) {
            throw new IllegalStateException("failed to create a child event loop", e);
        } finally {
            // ========== 5. 如果创建失败,需要清理已经创建的 NioEventLoop ==========
            if (!success) {
                // 关闭已经创建成功的 EventLoop
                for (int j = 0; j < i; j ++) {
                    children[j].shutdownGracefully();
                }

                // 等待它们完全终止
                for (int j = 0; j < i; j ++) {
                    EventExecutor e = children[j];
                    try {
                        while (!e.isTerminated()) {
                            e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
                        }
                    } catch (InterruptedException interrupted) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }
    }

    // ========== 6. 创建 Chooser,用于从 children 数组中选择 EventLoop ==========
    chooser = chooserFactory.newChooser(children);

    // ========== 7. 设置终止监听器 ==========
    final FutureListener<Object> terminationListener = new FutureListener<Object>() {
        @Override
        public void operationComplete(Future<Object> future) throws Exception {
            // 当所有 EventLoop 都终止时,设置 terminationFuture 为成功
            if (terminatedChildren.incrementAndGet() == children.length) {
                terminationFuture.setSuccess(null);
            }
        }
    };
    
    // 给每个 EventLoop 添加终止监听器
    for (EventExecutor e: children) {
        e.terminationFuture().addListener(terminationListener);
    }

    // ========== 8. 创建只读的 children 集合 ==========
    Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
    Collections.addAll(childrenSet, children);
    readonlyChildren = Collections.unmodifiableSet(childrenSet);
}

让我们逐步解析这个方法:

3.1 参数校验
if (nThreads <= 0) {
    throw new IllegalArgumentException(
        String.format("nThreads: %d (expected: > 0)", nThreads));
}

很简单,线程数必须大于 0。

3.2 创建 children 数组
children = new EventExecutor[nThreads];

这是 NioEventLoopGroup 的核心数据结构,用于存储所有的 NioEventLoop 实例。

比如你创建了 4 个线程:

children[0] = NioEventLoop-0
children[1] = NioEventLoop-1
children[2] = NioEventLoop-2
children[3] = NioEventLoop-3
3.3 循环创建 NioEventLoop
for (int i = 0; i < nThreads; i ++) {
    children[i] = newChild(executor, args);
}

newChild() 方法在 NioEventLoopGroup 中的实现:

@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
    // args[0] = SelectorProvider
    // args[1] = SelectStrategyFactory
    // args[2] = RejectedExecutionHandler
    return new NioEventLoop(this, executor, (SelectorProvider) args[0],
        ((SelectStrategyFactory) args[1]).newSelectStrategy(),
        (RejectedExecutionHandler) args[2]);
}

通俗解释:

  • 循环 nThreads 次,每次创建一个 NioEventLoop
  • 每个 NioEventLoop 都会被赋予:
    • 父 Group(this)
    • 线程创建器(executor)
    • Selector 提供者(selectorProvider)
    • 选择策略(selectStrategy)
    • 拒绝策略(rejectedExecutionHandler)
3.4 异常处理机制
finally {
    if (!success) {
        // 关闭已经创建成功的 EventLoop
        for (int j = 0; j < i; j ++) {
            children[j].shutdownGracefully();
        }
        // 等待它们完全终止
        for (int j = 0; j < i; j ++) {
            EventExecutor e = children[j];
            try {
                while (!e.isTerminated()) {
                    e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
                }
            } catch (InterruptedException interrupted) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
}

通俗解释:

  • 如果创建 NioEventLoop 的过程中出现异常,需要清理已经创建的 EventLoop
  • 比如创建了 3 个,第 4 个失败了,那么需要关闭前 3 个
  • 这是一种资源清理机制,防止资源泄漏
3.5 创建 Chooser
chooser = chooserFactory.newChooser(children);

创建线程选择器,用于从 children 数组中选择 NioEventLoop。

3.6 设置终止监听器
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
    @Override
    public void operationComplete(Future<Object> future) throws Exception {
        if (terminatedChildren.incrementAndGet() == children.length) {
            terminationFuture.setSuccess(null);
        }
    }
};

for (EventExecutor e: children) {
    e.terminationFuture().addListener(terminationListener);
}

通俗解释:

  • 给每个 NioEventLoop 添加一个监听器
  • 当一个 NioEventLoop 终止时,terminatedChildren 计数器加 1
  • 当所有 NioEventLoop 都终止时,设置 terminationFuture 为成功
  • 这样外部就可以通过 terminationFuture 来等待整个 Group 关闭
3.7 创建只读集合
Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);

创建一个只读的 Set,防止外部修改 children 数组。

四、NioEventLoopGroup 的核心方法

初始化完成后,NioEventLoopGroup 就可以使用了。我们来看看它的核心方法:

4.1 next() - 选择一个 EventLoop

@Override
public EventLoop next() {
    return (EventLoop) chooser.next();
}

通俗解释:

  • 使用 Chooser 从 children 数组中选择一个 NioEventLoop
  • 选择策略是轮询(Round-Robin)
  • 每次调用 next() 都会返回下一个 EventLoop

使用场景:

// 当有新连接时,选择一个 EventLoop 来处理
EventLoop eventLoop = workerGroup.next();
eventLoop.register(channel);

4.2 register() - 注册 Channel

@Override
public ChannelFuture register(Channel channel) {
    return next().register(channel);
}

通俗解释:

  • 选择一个 EventLoop,然后将 Channel 注册到这个 EventLoop 上
  • 一旦注册,这个 Channel 就会一直由这个 EventLoop 处理

4.3 shutdownGracefully() - 优雅关闭

@Override
public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
    // 关闭所有的 EventLoop
    for (EventLoop l: children) {
        l.shutdownGracefully(quietPeriod, timeout, unit);
    }
    return terminationFuture();
}

通俗解释:

  • 关闭所有的 NioEventLoop
  • 每个 EventLoop 会先处理完队列中的任务,然后再关闭
  • 返回一个 Future,可以用来等待所有 EventLoop 关闭完成

五、完整的初始化流程图

让我们用一张图来总结整个初始化过程:

new NioEventLoopGroup(4)
         |
         v
步骤1: 确定线程数 = 4
         |
         v
步骤2: 创建 ThreadPerTaskExecutor
         |
         v
步骤3: 创建 PowerOfTwoEventExecutorChooser (因为 4 是 2 的幂次方)
         |
         v
步骤4: 创建 SelectorProvider
         |
         v
步骤5: 创建 DefaultSelectStrategy
         |
         v
步骤6: 创建 RejectedExecutionHandler
         |
         v
步骤7: 创建 children 数组并初始化
         |
         +---> 创建 NioEventLoop-0
         |       |
         |       +---> 创建 Selector-0
         |       +---> 创建 TaskQueue-0
         |
         +---> 创建 NioEventLoop-1
         |       |
         |       +---> 创建 Selector-1
         |       +---> 创建 TaskQueue-1
         |
         +---> 创建 NioEventLoop-2
         |       |
         |       +---> 创建 Selector-2
         |       +---> 创建 TaskQueue-2
         |
         +---> 创建 NioEventLoop-3
                 |
                 +---> 创建 Selector-3
                 +---> 创建 TaskQueue-3

六、总结

通过这篇文章,我们深入学习了 NioEventLoopGroup 的源码实现:

  1. NioEventLoopGroup 是什么:Netty 的线程池实现,专为 NIO 设计
  2. 核心组件:children 数组、Chooser、Executor、SelectorProvider 等
  3. 初始化过程:7 个步骤,从参数设置到创建 NioEventLoop
  4. 核心方法:next()、register()、shutdownGracefully()
  5. 设计思想:固定线程数、线程绑定、轮询选择

希望这篇文章能帮助你理解 NioEventLoopGroup 的源码实现。如果你想深入学习,建议继续阅读 NioEventLoop 的源码,了解单个线程是如何工作的。


推荐阅读:

  • NioEventLoop 运行机制详解
  • Netty 服务端启动流程详解
  • Netty Channel 注册流程详解

如果这篇文章对你有帮助,欢迎点赞、收藏、分享!

本文详细介绍了 NioEventLoopGroup 的源码实现,更多 Netty 源码解析请查看 NioEventLoopGroup深度解析.md 文档。

Netty EventLoopGroup 详解:Nio、Epoll、Poll 、KQueue和IoUring Netty 是一个高性能的网络通信框架,它使用 EventLoopGroup 来处理 I/O 事件。不同的 EventLoopGroup 实现针对不同的操作系统和应用场景优化性能。和,并提供了详细的代码示例和注释。 阅读详情

相关推荐

netty案例,netty4.1源码分析篇一《NioEventLoopGroup源码分析》

本章节我们从一个基础构建的基础NettyServer来分析NioEventLoopGroup源码,其中包括了;EventLoopGroup事件循环组、NioEventLoopGroup异步事件循环组、MultithreadEventLoopGroup多线程事件循环组等。 启动NettyServer的模版代码 private void bing(int port) { EventLoopGro...

bugstack虫洞栈 1910

NioEventLoopGroup初始化

本文是我对Netty的NioEventLoopGroup及NioEventLoop初始化工作的源码阅读笔记, 如下图,是Netty的Reactor线程模型图,本文描述NioEventLoopGroup等价于我在图中标红的MainReactor组件,全篇围绕它的初始化展开,难免地方理解的不正确,欢迎留言 在Nio网络编程模型的图示是下面那张图, 单条Thread全职执行一个Selecto...

weixin_30606669的博客 481

【OWL部署】Manus又一开源平替OWL真的很好用吗?手把手带你部署并运行你的AI助手OWL(对接Qwen、硅基流动接口)

本文介绍了通用人工智能OWL的部署及国内接口对接,全篇干货满满,手把手教学。

MosuoLc的博客 4046

Netty中NioEventLoopGroup介绍

Netty中的核心类之一的:NioEventLoopGroup

小飞侠的博客 2413

拆开华为BBU5900,看看5G基站的大脑里到底装了啥?

本文深度拆解华为BBU5900,揭示5G基站核心处理单元的硬件架构与设计哲学。通过详细解析模块化设计、智能电源系统和动态散热方案,展现其支撑千兆速率、毫秒级时延的技术奥秘,为5G网络部署提供实用参考。

weixin_31456563的博客 564

Python经典编程习题100例:第32例:相反顺序输出列表

不要自卑,去提升实力 互联网行业谁技术牛谁是爹 如果文章可以带给你能量,那是最好的事!请相信自己 加油o~ 本人初学Python,只为熟悉语法编写,大神请勿理会 点击下面链接 Python经典编程100例习题汇总 题目描述: 按相反的顺序输出列表的值。 解题思路: > 利用reverse函数逆序 代码: arr=['f','g','e','b'] print(arr) arr.reverse() print(arr) ...

优快云 精品推荐 1419

Netty系列-1 NioEventLoopGroup和NioEventLoop介绍

本文从源码的角度介绍NioEventLoopGroup和NioEventLoop,包含NioEventLoopGroup和NioEventLoop内部的组件。

shengyu 2176

第一节:初识n8n与下一代工作流自动化

本章介绍了n8n的Fair-code理念与节点式架构,对比了其与Zapier/Make的核心差异,并引导读者在n8n Cloud上完成首次界面导览,建立了工作流自动化的宏观认知。

easeyoo的专栏 107

NioEventLoopGroup

目录 summary first second Summary NioEventLoopGroup是MultithreadEventLoopGroup这个抽象类的具体实现、其专门是为注册到Selector上的Channel服务、当某个Channel上的事件ready(包括但不局限于、read/write/listen)后、具体的线程就是由NioEventLoopGroup提供用...

qq_32259579的博客 883

SillyTavern 酒馆在 Mac 和 Linux 上的部署教程(含启动器安装方法)

SillyTavern 是一个支持多种大模型聊天接口的本地前端项目,适用于 MacOS 和 Linux 系统。本文提供了两种部署方式:手动安装和使用 SillyTavern Launcher 安装器。手动安装需要先安装 Git 和 NodeJS,然后克隆项目源码并运行启动脚本。使用 Launcher 则更为简便,适合新手用户,能够自动安装依赖和配置环境。部署完成后,用户可以通过浏览器访问本地服务器,加载角色卡片并连接大模型 API,享受二次元角色扮演聊天的乐趣。无论是开发者还是终端用户,都能轻松完成 Sil

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 3396

移花接木,玩转CANoe的几种扩展接口应用(五)——串口设备

近期看到粉丝朋友在CANoe自动化测试方面的关注度很大,今天就围绕这个做一个专题,总结一下以往项目上用过的几种CANoe扩展接口,分享出来希望对相关领域的网友有所帮助。本文是该专题的第五篇文章,主要讲解了串口设备的功能配置、连接方法、配置方法、调用方法,最后分析了这种扩展借口应用的特点和适用场景。

Mr.Cssust的博客 2369

Netty学习笔记通信调度篇:NioEventLoopGroup源码分析

目录 NioEventLoopGroup类层次结构 MultithreadEventExecutorGroup EventExecutorChooser FastThreadLocalRunnable 在创建主从Reactor多线程模型的Netty服务端时,服务端的代码如下: EventLoopGroup bossGroup = new NioEventLoopGro...

船长 725

LDRA Testbed软件静态分析_常见问题及处理

通过前面的几篇文章,LDRA Testbed软件静态分析的内容基本讲解完了,本篇文章将针对使用Testbed进行软件静态分析的常见问题进行介绍。 到此为止,LDRA Testbed软件静态分析的内容已经全部讲完,如果有问题,欢迎私信提问(不经常登录,回复可能不及时,见谅)。下一篇文章将开始讲解如何使用Testbed进行单元测试。

文章主要涉及嵌入式软件开发、测试、项目管理等,欢迎交流,共同进步。 2591

Netty篇:Reactor线程模型和NioEventLoop,NioEventLoopGroup源码分析

Reactor线程模型简单描述,NioEventLoop,NioEventLoopGroup源码简单分析

走在路上 475

AUTOSAR从入门到精通-汽车电子电气架构(EEA)

EEA(Electrical/Electronic Architecture),电子电气架构,是首先由德尔福公司提出的,集合汽车的电子电气系统原理设计、中央电器盒的设计、连接器的设计、电子电气分配系统等设计为一体的整车电子电气解决方案的概念。通过EEA的设计,可将动力总成、驱动信息、娱乐信息等车身信息转化为实际的电源分配的物理布局、信号网络、数据网络、诊断、容错、能量管理等的电子电气解决方案。

getusushu的博客 862

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

TPS259483与TM4C129电源路径保护系统设计实战

电子保险丝(eFuse)是现代嵌入式系统电源路径管理的核心器件,其本质是集过流检测、快速关断、状态反馈于一体的智能功率开关。工作原理基于高精度电流采样+微秒级比较器响应+MOSFET栅极驱动闭环,技术价值在于将传统保险丝的被动熔断升级为可编程、可监控、可恢复的主动防护。典型应用场景涵盖工业PLC模块、USB-C PD设备、边缘网关等对供电可靠性要求严苛的领域。本文聚焦TI TPS259483电子保险丝与TM4C129 MCU协同实现硬件级快速保护与软件级策略决策的深度融合,详解23μs级过流响应、±3%限流

weixin_34121282的博客 370

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Netty Review - NioEventLoopGroup源码解析

这段代码是在使用Netty框架时常见的用法,用于创建两个不同的实例,一个用于处理连接请求(通常称为bossGroup),另一个用于处理连接后的数据流(通常称为workerGroup)。是Netty中用于处理NIO事件的的实现之一。在Netty中,事件循环(EventLoop)是Netty的核心,负责处理各种事件,比如接收连接、读取数据、写入数据等。其主要功能和构造函数参数的含义:第一个构造函数参数表示创建的EventLoop的数量。

小工匠 8274

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

netty之NioEventLoopGroup

Netty的NioEventLoopGroup及NioEventLoop初始化工作的源码阅读笔记, 如下图,是Netty的Reactor线程模型图,本文描述NioEventLoopGroup等价于我在图中标红的MainReactor组件,全篇围绕它的初始化展开,难免地方理解的不正确 在Nio网络编程模型的图示是下面那张图, 单条Thread全职执行一个Selector,首先是服务端在启动的时候,会把代表服务端的ServerSockerChannel注册进Selector,且感兴趣的事件是Accept, 一

追逐消失的记忆 1万+

吃透Netty源码系列一之NioEventLoopGroup

Netty源码深度解析系列一前言Netty的Reactor模式 前言 netty更新的是快,最新发布版本已经是4.1.45.Final了,以前有学过netty,觉得学的还不够深入,这次打算从源码级别去更加深入的理解内部机制。我不想介绍太多关于netty是什么,怎么用,我更想介绍一下原理,这样才能更好的去使用它,扩展它,完善它。我打算从常用的一些类开始介绍,比如NioEventLoopGroup S...

王伟王胖胖的博客 5662

Netty之NioEventLoopGroup源码分析

本文是对Netty中NioEventLoopGroup的简单分析,该类是连接接入的入口,它负责新连接的接入与连接事件的处理,接下来我会从使用它的角度去分析该类的作用,通过本文你将了解到Netty是如何创建线程去处理连接的,如果文章中有错误希望能够指出,谢谢。 NioEventLoopGroup之大管家 我们在编写Netty服务的时候,首先会创建bossGroup与workerGroup,如下...

qq_37803406的博客 502

Netty源码分析系列之NioEventLoop

这里从我们之前创建Netty服务端和客户端例子出发(第一个就是创建NioEventLoopGroup对象)出发 本篇文章分析了Netty的三种经典的Reactor线程模型,同时分析了线程模型的实现类NioEventLoop从其创建和启动两个角度对该类进行详细的分析,希望对读者学习netty框架有所帮助

liushangzaibeijing的博客 5万+

netty源码分析5-NioEventLoopGroup

分享内容如下: NioEventLoopGroup初始化分析 NioEventLoopGroup父子类分析 parentGroup与childGroup区别 1.NioEventLoopGroup初始化分析 从接口类图上看 EventLoopGroup 继承了 线程池和定时线程池功能,判断EventLoopGroup具有线程池的复合功能。从命名猜测 EventLoopGroup 管理了一组...

chenchangqun11的专栏 565

拆解 nRF24_jammer 源码:ESP32 如何通过共享 SPI 并行驱动多块 nRF24 模块

nRF24_jammer 是一款基于 ESP32 的 RF 干扰器,支持用可配置数量的 nRF24L01+ 模块干扰蓝牙、BLE、无人机遥控、Wi-Fi 与 Zigbee。它的工程亮点在于:用**一条共享 SPI 总线**驱动多块 nRF24 模块,仅靠每块芯片独立的 CE/CSN 引脚就能并行工作。本文带你从硬件接线到源码关键函数,完整拆解这套设计。 ## 为什么要"共享 SPI"?先看硬件接

gitblog_00113的博客 447

Netty——NioEventLoopGroup源码分析

摘要 提到Netty首当其冲被提起的肯定是支持它承受高并发的线程模型,说到线程模型就不得不提到NioEventLoopGroup这个线程池。 线程模型 Netty的线程模型被称为Reactor模型,具体如图所示,图上的mainReactor指的就是bossGroup,这个线程池处理客户端的连接请求,并将accept的连接注册到subReactor的其中一个线程上;图上的subReactor当然指的就是workerGroup,负责处理已建立的客户端通道上的数据读写;图上还有一块ThreadPool是具体

庄小焱 529

NioEventLoopGroup 源码分析

NioEventLoopGroup 源码分析1. 在阅读源码时做了一定的注释,并且做了一些测试分析源码内的执行流程,由于博客篇幅有限。为了方便 IDE 查看、跟踪、调试 代码,所以在 github上提供 netty 的源码、详细的注释及测试用例。欢迎大家 star、fork !2. 由于个人水平有限,对源码的分析理解可能存在偏差或不透彻的地方还请大家在评论区指出,谢谢!从今天开始,就准备进军 ne...

James的博客 1011

netty : NioEventLoopGroup 源码分析

NioEventLoopGroup 源码分析 1. 在阅读源码时做了一定的注释,并且做了一些测试分析源码内的执行流程,由于博客篇幅有限。为了方便 IDE 查看、跟踪、调试 代码,所以在 github 上提供 netty 的源码、详细的注释及测试用例。欢迎大家 star、fork ! 2. 由于个人水平有限,对源码的分析理解可能存在偏差或不透彻的地方还请大家在评论区指出,谢谢! ...

昨夜凛雨 367
上一篇: Netty源码分析篇:Netty Pipeline 初始化流程
下一篇: Netty源码分析篇:Channel 的 register 操作
不早睡不改名@
博客等级 码龄5年 536粉丝 306原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值