Netty源码分析---NioEventLoopGroup深度解析

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

相关文章链接

位运算详解

waken方法详解

ThreadPerTaskExecutor与线程创建详解

processSelectedKeys() vs runAllTasks()

NioServerSocketChannel-Unsafe初始化详解

NioEventLoop的run方法详解

NioEventLoopGroup深度解析

inEventLoop方法详解

executionMask详解

Netty源码分析–认真系列(一)

Netty源码分析–认真系列(二)

NioEventLoopGroup 深度解析

本文详细介绍 Netty 中的线程池 NioEventLoopGroup 的设计原理、核心参数、创建流程以及与 NioEventLoop 的关系。

一、NioEventLoopGroup 是什么?

1.1 本质定义

NioEventLoopGroup 是 Netty 中的线程池实现,但它不是传统意义上的 ThreadPoolExecutor,而是专门为事件驱动的 NIO 模型设计的线程池。

从类的命名可以看出:

  • Group:表示这是一个组,一个集合
  • EventLoop:表示组中的每个元素都是事件循环
  • Nio:表示基于 Java NIO 实现

1.2 核心概念对应关系

NioEventLoopGroup(线程池)
    ├── NioEventLoop(线程1)
    ├── NioEventLoop(线程2)
    ├── NioEventLoop(线程3)
    └── ...

重要理解:

  • NioEventLoopGroup = 线程池(管理者)
  • NioEventLoop = 线程池中的单个"线程"(工作者)
  • 每个 NioEventLoop 内部有一个真正的 Thread 实例

1.3 在 Netty 中的使用场景

// 服务端典型用法
EventLoopGroup bossGroup = new NioEventLoopGroup(1);      // 负责接收连接
EventLoopGroup workerGroup = new NioEventLoopGroup();     // 负责处理 IO

// 客户端典型用法
EventLoopGroup group = new NioEventLoopGroup();           // 负责连接和 IO

bossGroup 和 workerGroup 的职责划分:

  • bossGroup:专门负责监听 OP_ACCEPT 事件,接收客户端连接
  • workerGroup:负责处理已建立连接的 OP_READ、OP_WRITE 等 IO 事件

二、NioEventLoopGroup 的继承体系

2.1 完整的继承链

NioEventLoopGroup
    ↓ extends
MultithreadEventLoopGroup
    ↓ extends
MultithreadEventExecutorGroup
    ↓ extends
AbstractEventExecutorGroup
    ↓ implements
EventLoopGroup
    ↓ extends
EventExecutorGroup
    ↓ extends
ScheduledExecutorService, Iterable<EventExecutor>

2.2 关键接口和抽象类的作用

EventExecutorGroup(顶层接口)
  • 继承自 JDK 的 ScheduledExecutorService
  • 提供了线程池的基本能力:提交任务、调度任务、关闭线程池等
  • 增加了 next() 方法:从线程池中选择一个 EventExecutor
EventLoopGroup(事件循环组接口)
  • 继承自 EventExecutorGroup
  • 增加了 register(Channel) 方法:将 Channel 注册到某个 EventLoop 上
  • 这是 Netty 特有的,将 Channel 和线程池关联起来
MultithreadEventExecutorGroup(多线程执行器组)
  • 这是核心实现类,实现了线程池的主要逻辑
  • 维护了 children 数组,存储所有的 EventExecutor(即 NioEventLoop)
  • 实现了线程选择逻辑(通过 Chooser)
MultithreadEventLoopGroup(多线程事件循环组)
  • 继承自 MultithreadEventExecutorGroup
  • 设置了默认线程数:CPU 核心数 * 2
  • 实现了 register(Channel) 方法
NioEventLoopGroup(NIO 事件循环组)
  • 最终的实现类
  • 覆写了 newChild() 方法,创建 NioEventLoop 实例
  • 设置了 NIO 相关的默认参数(SelectorProvider、SelectStrategy 等)

三、NioEventLoopGroup 的构造过程详解

3.1 构造方法的重载链

// 1. 无参构造(最常用)
public NioEventLoopGroup() {
    this(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());
}

3.2 构造过程中的参数设置

第一步:设置线程数(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));
}

关键点:

  • 默认线程数 = CPU 核心数 * 2
  • 可以通过系统属性 io.netty.eventLoopThreads 自定义
  • 最小值为 1

为什么是 CPU 核心数 * 2?

  • NIO 是 IO 密集型操作,线程经常会阻塞在 select() 上
  • 适当增加线程数可以提高并发处理能力
  • 但也不能太多,避免线程切换开销
第二步:设置 Executor
// 在 MultithreadEventExecutorGroup 中
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
    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();
    }
}

重要理解:

  • ThreadPerTaskExecutor 不是传统的线程池,它每次都创建新线程
  • 这个 Executor 不是给 NioEventLoopGroup 用的
  • 而是给每个 NioEventLoop 用的,用于创建 NioEventLoop 内部的那个唯一线程
  • 每个 NioEventLoop 只会调用一次 executor.execute(),创建自己的工作线程

为什么这样设计?

  • NioEventLoop 需要一个长期运行的线程来执行事件循环
  • 这个线程不能被线程池回收,必须是专属的
  • 使用 ThreadPerTaskExecutor 可以灵活控制线程的创建(线程名、优先级等)
第三步:设置 EventExecutorChooserFactory
// 在 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)) {
            return new PowerOfTwoEventExecutorChooser(executors);
        } else {
            return new GenericEventExecutorChooser(executors);
        }
    }
    
    private static boolean isPowerOfTwo(int val) {
        return (val & -val) == val;
    }
}

两种选择策略:

  1. PowerOfTwoEventExecutorChooser(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];
    }
}
  1. GenericEventExecutorChooser(通用选择器)
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)];
    }
}

为什么要区分两种策略?

  • 当线程数是 2 的幂次方时,x % n 等价于 x & (n-1)
  • 位运算比取模运算快得多
  • 这是一个性能优化的细节

选择策略的作用:

  • 当有新的 Channel 需要注册时,通过 chooser.next() 选择一个 NioEventLoop
  • 采用轮询(Round-Robin)的方式,保证负载均衡
  • 例如:线程池有 4 个线程,依次选择 0 -> 1 -> 2 -> 3 -> 0 -> 1 …
第四步:设置 SelectorProvider
public NioEventLoopGroup(int nThreads, Executor executor) {
    this(nThreads, executor, SelectorProvider.provider());
}

SelectorProvider 的作用:

  • 这是 JDK NIO 提供的类,用于创建 Selector、ServerSocketChannel、SocketChannel 等
  • SelectorProvider.provider() 返回平台默认的实现
  • 在 Windows 上是 WindowsSelectorProvider
  • 在 Linux 上是 EPollSelectorProvider(如果支持 epoll)

为什么需要 SelectorProvider?

  • 每个 NioEventLoop 都需要一个 Selector 实例
  • Selector 不能直接 new,必须通过 SelectorProvider 创建
  • 这样可以保证使用平台最优的实现
// 在 NioEventLoop 的构造方法中会使用
Selector selector = selectorProvider.openSelector();
第五步:设置 SelectStrategyFactory
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 在事件循环中是执行阻塞的 select() 还是非阻塞的 selectNow()
  • 如果任务队列中有任务,使用 selectNow() 快速返回,优先处理任务
  • 如果任务队列为空,使用 select() 阻塞等待 IO 事件

这是一个重要的性能优化:

  • 避免在有任务等待时,线程阻塞在 select() 上
  • 保证任务能够及时被执行
第六步:设置 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();
        }
    };
}

拒绝策略的触发时机:

  • 每个 NioEventLoop 内部有一个任务队列(taskQueue),默认容量是 16
  • 当任务队列满了,再提交任务时,会触发拒绝策略
  • 默认策略是直接抛出 RejectedExecutionException

为什么任务队列容量这么小?

  • NioEventLoop 的设计理念是快速处理 IO 事件
  • 不应该有大量任务堆积在队列中
  • 如果队列满了,说明系统负载过高,应该及时发现问题

3.3 MultithreadEventExecutorGroup 的核心构造逻辑

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

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 为 null,创建默认的 ThreadPerTaskExecutor
    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 {
            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);
}

上述代码的关键点详解:

children 数组(最核心)
children = new EventExecutor[nThreads];
  • 这是 NioEventLoopGroup 最核心的数据结构
  • 数组长度就是线程池的大小
  • 每个元素都是一个 NioEventLoop 实例
  • 后续所有的操作都是基于这个数组
newChild() 方法
// 在 NioEventLoopGroup 中覆写
@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
    return new NioEventLoop(this, executor, (SelectorProvider) args[0],
        ((SelectStrategyFactory) args[1]).newSelectStrategy(), 
        (RejectedExecutionHandler) args[2]);
}
  • 这个方法负责创建单个 NioEventLoop 实例
  • 传入的参数包括:
    • this:NioEventLoopGroup 自己,作为 parent
    • executor:ThreadPerTaskExecutor,用于创建线程
    • SelectorProvider:用于创建 Selector
    • SelectStrategy:选择策略
    • RejectedExecutionHandler:拒绝策略
异常处理机制
if (!success) {
    // 关闭已经创建成功的 EventLoop
    for (int j = 0; j < i; j ++) {
        children[j].shutdownGracefully();
    }
    // 等待它们完全终止
    ...
}
  • 如果某个 NioEventLoop 创建失败,需要清理已经创建的
  • 这是一种"要么全部成功,要么全部失败"的策略
  • 保证线程池的状态一致性
终止监听器
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
    @Override
    public void operationComplete(Future<Object> future) throws Exception {
        if (terminatedChildren.incrementAndGet() == children.length) {
            terminationFuture.setSuccess(null);
        }
    }
};
  • 当所有的 NioEventLoop 都终止后,整个 NioEventLoopGroup 才算终止
  • 使用计数器 terminatedChildren 来跟踪已终止的 EventLoop 数量
  • 当计数器等于 children.length 时,设置 terminationFuture 为成功

四、NioEventLoop 的创建过程

4.1 NioEventLoop 的构造方法

NioEventLoop(NioEventLoopGroup parent, Executor executor, 
             SelectorProvider selectorProvider,
             SelectStrategy strategy, 
             RejectedExecutionHandler rejectedExecutionHandler) {
    // 调用父类构造方法
    super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
    
    if (selectorProvider == null) {
        throw new NullPointerException("selectorProvider");
    }
    if (strategy == null) {
        throw new NullPointerException("selectStrategy");
    }
    
    // 保存 SelectorProvider
    provider = selectorProvider;
    
    // 创建 Selector(NIO 的核心组件)
    final SelectorTuple selectorTuple = openSelector();
    selector = selectorTuple.selector;
    unwrappedSelector = selectorTuple.unwrappedSelector;
    
    // 保存选择策略
    selectStrategy = strategy;
}

4.2 NioEventLoop 的核心属性

public final class NioEventLoop extends SingleThreadEventLoop {
    
    // ========== NIO 相关 ==========
    // Selector,NIO 的核心,用于监听 IO 事件
    private Selector selector;
    private Selector unwrappedSelector;
    
    // 优化后的 SelectedKeys 集合
    private SelectedSelectionKeySet selectedKeys;
    
    // SelectorProvider,用于创建 Selector
    private final SelectorProvider provider;
    
    // 唤醒标记,用于唤醒阻塞在 select() 上的线程
    private final AtomicBoolean wakenUp = new AtomicBoolean();
    
    // 选择策略
    private final SelectStrategy selectStrategy;
    
    // ========== 性能调优相关 ==========
    // IO 操作和非 IO 操作的时间比例,默认 50
    // 表示 IO 操作和处理任务的时间比例是 1:1
    private volatile int ioRatio = 50;
    
    // 取消的 Key 数量
    private int cancelledKeys;
    
    // 是否需要再次 select
    private boolean needsToSelectAgain;
}

4.3 SingleThreadEventLoop 的构造方法

protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor,
                                boolean addTaskWakesUp, int maxPendingTasks,
                                RejectedExecutionHandler rejectedExecutionHandler) {
    // 调用父类构造方法
    super(parent, executor, addTaskWakesUp, maxPendingTasks, rejectedExecutionHandler);

    // tailTasks 是一个特殊的任务队列,在每次事件循环的最后执行
    // 通常用于一些清理工作,我们可以暂时忽略它
    tailTasks = newTaskQueue(maxPendingTasks);
}

4.4 SingleThreadEventExecutor 的构造方法(最核心)

protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
                                    boolean addTaskWakesUp, int maxPendingTasks,
                                    RejectedExecutionHandler rejectedHandler) {
    super(parent);
    
    // addTaskWakesUp:添加任务时是否需要唤醒线程
    // 对于 NioEventLoop,这个值是 false
    this.addTaskWakesUp = addTaskWakesUp;
    
    // 最大待处理任务数,默认是 16
    this.maxPendingTasks = Math.max(16, maxPendingTasks);
    
    // 保存 executor,用于创建线程
    this.executor = ObjectUtil.checkNotNull(executor, "executor");
    
    // 创建任务队列,这是一个非常重要的队列
    taskQueue = newTaskQueue(this.maxPendingTasks);
    
    // 拒绝策略
    rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}

关键属性详解:

taskQueue(任务队列)
taskQueue = newTaskQueue(this.maxPendingTasks);

protected Queue<Runnable> newTaskQueue(int maxPendingTasks) {
    // 默认使用 MpscQueue(Multiple Producer Single Consumer Queue)
    // 多生产者单消费者队列,针对 Netty 的使用场景优化
    return new MpscUnboundedArrayQueue<Runnable>(maxPendingTasks);
}
  • 这是 NioEventLoop 中最重要的队列之一
  • 用于存储提交给 NioEventLoop 的任务
  • 默认初始容量是 16,但可以动态扩容(Unbounded)
  • 使用 MPSC 队列,支持多个线程同时提交任务,但只有一个线程消费

taskQueue 的作用:

  1. 存储用户提交的任务(通过 execute(Runnable) 方法)
  2. 存储 Netty 内部的任务(如 register、bind、connect 等)
  3. 在事件循环中,会定期从这个队列中取出任务执行
executor(线程创建器)
this.executor = ObjectUtil.checkNotNull(executor, "executor");
  • 这就是前面创建的 ThreadPerTaskExecutor
  • 它的作用是创建 NioEventLoop 的工作线程
  • 注意:此时线程还没有创建
  • 线程会在第一个任务提交时才创建(延迟创建)
thread(工作线程)
// 在 SingleThreadEventExecutor 中
private volatile Thread thread;
  • 这是 NioEventLoop 真正的工作线程
  • 初始值为 null,在第一次执行任务时才会创建
  • 一旦创建,就会一直运行,直到 NioEventLoop 关闭
  • 这个线程会执行事件循环(run 方法)

4.5 openSelector() 方法详解

private SelectorTuple openSelector() {
    final Selector unwrappedSelector;
    try {
        // 通过 SelectorProvider 创建 Selector
        unwrappedSelector = provider.openSelector();
    } catch (IOException e) {
        throw new ChannelException("failed to open a new selector", e);
    }

    // 如果禁用了 Selector 优化,直接返回
    if (DISABLE_KEY_SET_OPTIMIZATION) {
        return new SelectorTuple(unwrappedSelector);
    }

    // 下面是 Netty 对 Selector 的优化
    // 将 Selector 内部的 selectedKeys 替换为 Netty 优化的实现
    // 这部分是性能优化,可以提高 select 后遍历 keys 的效率
    
    Object maybeSelectorImplClass = AccessController.doPrivileged(...);
    
    // 通过反射替换 selectedKeys 和 publicSelectedKeys
    final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
    
    // ... 反射代码省略 ...
    
    selectedKeys = selectedKeySet;
    
    return new SelectorTuple(unwrappedSelector,
                             new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
}

Selector 优化的原理:

  • JDK 原生的 Selector 使用 HashSet 存储 selectedKeys
  • Netty 使用数组实现的 SelectedSelectionKeySet,遍历效率更高
  • 通过反射将 Selector 内部的 selectedKeys 替换为 Netty 的实现

五、NioEventLoopGroup 的核心方法

5.1 register(Channel) 方法

这是 NioEventLoopGroup 最重要的方法,用于将 Channel 注册到某个 NioEventLoop 上。

// MultithreadEventLoopGroup
@Override
public ChannelFuture register(Channel channel) {
    // 通过 next() 方法选择一个 EventLoop
    return next().register(channel);
}

next() 方法的实现:

// MultithreadEventExecutorGroup
@Override
public EventExecutor next() {
    // 使用 chooser 选择一个 EventLoop
    return chooser.next();
}

完整的调用链:

NioEventLoopGroup.register(channel)
    ↓
next() 选择一个 NioEventLoop
    ↓
NioEventLoop.register(channel)
    ↓
将 channel 注册到这个 NioEventLoop 的 Selector 上

关键点:

  • 一个 Channel 只会注册到一个 NioEventLoop 上
  • 一旦注册,这个 Channel 的所有 IO 事件都由这个 NioEventLoop 处理
  • 这保证了线程安全,避免了多线程竞争

5.2 execute(Runnable) 方法

虽然 NioEventLoopGroup 实现了 Executor 接口,但通常我们不会直接调用它的 execute 方法。

// MultithreadEventExecutorGroup
@Override
public void execute(Runnable command) {
    // 选择一个 EventLoop 来执行任务
    next().execute(command);
}

更常见的用法是直接在 NioEventLoop 上执行任务:

channel.eventLoop().execute(() -> {
    // 这个任务会在 channel 所属的 NioEventLoop 中执行
    System.out.println("Task executed in " + Thread.currentThread().getName());
});

5.3 shutdownGracefully() 方法

优雅关闭线程池的方法。

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

优雅关闭的流程:

  1. 停止接收新任务
  2. 等待已提交的任务执行完成
  3. 在 quietPeriod 时间内,如果没有新任务,则关闭
  4. 如果超过 timeout 时间,强制关闭

六、NioEventLoopGroup 的重要特性总结

6.1 线程模型

NioEventLoopGroup(线程池)
    ├── NioEventLoop-1(线程1)
    │   ├── Thread-1(真正的线程)
    │   ├── Selector-1(NIO Selector)
    │   ├── taskQueue-1(任务队列)
    │   └── 管理多个 Channel
    │
    ├── NioEventLoop-2(线程2)
    │   ├── Thread-2
    │   ├── Selector-2
    │   ├── taskQueue-2
    │   └── 管理多个 Channel
    │
    └── ...

关键特性:

  • 一个 NioEventLoop 对应一个线程
  • 一个 NioEventLoop 有一个 Selector
  • 一个 NioEventLoop 可以管理多个 Channel
  • 一个 Channel 只能注册到一个 NioEventLoop

6.2 线程安全性

NioEventLoop 的线程安全保证:

  • 每个 Channel 的所有操作都在同一个 NioEventLoop 中执行
  • 避免了多线程竞争,不需要加锁
  • 这是 Netty 高性能的关键之一

判断是否在 EventLoop 线程中:

if (channel.eventLoop().inEventLoop()) {
    // 当前线程就是 EventLoop 线程,直接执行
    doSomething();
} else {
    // 当前线程不是 EventLoop 线程,提交任务
    channel.eventLoop().execute(() -> doSomething());
}

6.3 任务执行模型

NioEventLoop 需要处理两类任务:

1. IO 任务
  • 监听 Selector 上的 IO 事件(OP_ACCEPT、OP_READ、OP_WRITE 等)
  • 处理这些 IO 事件(读取数据、写入数据等)
2. 非 IO 任务
  • 用户提交的任务(通过 execute 方法)
  • Netty 内部的任务(register、bind、connect 等)

ioRatio 参数:

private volatile int ioRatio = 50;
  • 控制 IO 任务和非 IO 任务的时间分配比例
  • 默认值 50,表示各占 50%
  • 如果 IO 操作耗时 100ms,那么处理非 IO 任务最多也是 100ms

为什么需要 ioRatio?

  • 防止某一类任务占用过多时间
  • 保证 IO 事件能够及时处理
  • 也保证用户任务能够及时执行

6.4 延迟创建线程

重要特性:NioEventLoop 的线程不是在构造时创建的,而是在第一个任务提交时创建。

// 创建 NioEventLoopGroup
EventLoopGroup group = new NioEventLoopGroup();
// 此时线程还没有创建

// 第一次提交任务时,才会创建线程
group.execute(() -> {
    System.out.println("First task");
});
// 此时线程已经创建并启动

为什么要延迟创建?

  • 避免创建不必要的线程
  • 如果某个 NioEventLoop 一直没有任务,就不会创建线程
  • 节省系统资源

线程创建的时机:

  • 第一次调用 execute(Runnable) 时
  • 第一次 register(Channel) 时
  • 这些操作都会触发 startThread() 方法

八、核心参数总结表

参数默认值作用调优建议
nThreadsCPU 核心数 * 2线程池大小bossGroup 设为 1,workerGroup 根据压测调整
ExecutorThreadPerTaskExecutor创建线程通常不需要自定义
ChooserFactoryDefaultEventExecutorChooserFactory选择 EventLoop不需要自定义
SelectorProvider平台默认实现创建 Selector不需要自定义
SelectStrategyFactoryDefaultSelectStrategyFactory选择策略不需要自定义
RejectedExecutionHandler抛出异常任务拒绝策略可以自定义为记录日志
ioRatio50IO 和非 IO 任务时间比根据业务调整,IO 密集型可以调高
maxPendingTasks16任务队列初始容量任务多时可以调大

十、深入理解:为什么这样设计?

10.1 为什么 NioEventLoop 是单线程的?

传统多线程模型的问题:

// 假设多个线程处理同一个 Channel
Thread-1: 读取数据 -> 处理 -> 写入响应
Thread-2: 读取数据 -> 处理 -> 写入响应
// 问题:需要加锁,性能下降,而且可能乱序

Netty 的单线程模型:

// 一个 Channel 绑定到一个 EventLoop
EventLoop-1: 读取数据 -> 处理 -> 写入响应
// 优势:无需加锁,保证顺序,性能更高

单线程模型的优势:

  1. 无锁化:同一个 Channel 的操作都在一个线程中,不需要加锁
  2. 顺序性:保证事件的处理顺序
  3. 简化编程:不需要考虑线程安全问题
  4. 高性能:避免了锁竞争和上下文切换

10.2 为什么需要 EventLoopGroup?

单个 EventLoop 的局限:

  • 一个线程只能处理有限的 Channel
  • 无法充分利用多核 CPU

EventLoopGroup 的优势:

  • 多个 EventLoop 并行工作
  • 每个 EventLoop 处理一部分 Channel
  • 充分利用多核 CPU

负载均衡:

10000 个 Channel
    ↓ 通过 Chooser 分配
EventLoop-1: 2500 个 Channel
EventLoop-2: 2500 个 Channel
EventLoop-3: 2500 个 Channel
EventLoop-4: 2500 个 Channel

10.3 为什么使用 Reactor 模式?

Reactor 模式的核心思想:

  • 使用 Selector 监听多个 Channel 的事件
  • 事件到达时,分发给对应的 Handler 处理
  • 一个线程可以处理多个连接

Netty 的实现:

NioEventLoop (Reactor)
    ↓
Selector.select() 监听事件
    ↓
有事件到达
    ↓
processSelectedKeys() 处理 IO 事件
    ↓
runAllTasks() 处理非 IO 任务
    ↓
循环往复

优势:

  • 一个线程可以管理成千上万个连接
  • 避免了传统 BIO 的一个连接一个线程的问题
  • 大大提高了系统的并发能力

十一、源码追踪:从创建到运行的完整流程

11.1 创建流程图

new NioEventLoopGroup()
    ↓
设置默认参数(nThreads、executor、chooserFactory 等)
    ↓
MultithreadEventExecutorGroup 构造方法
    ↓
创建 children 数组
    ↓
循环调用 newChild() 创建 NioEventLoop
    ↓
每个 NioEventLoop 创建时:
    - 创建 taskQueue
    - 创建 Selector
    - 保存 executor(用于后续创建线程)
    - 此时线程还未创建!
    ↓
创建 Chooser(用于选择 EventLoop)
    ↓
设置终止监听器
    ↓
NioEventLoopGroup 创建完成

11.2 第一次使用流程图

channel.register(eventLoopGroup)
    ↓
eventLoopGroup.next() 选择一个 NioEventLoop
    ↓
nioEventLoop.register(channel)
    ↓
nioEventLoop.execute(register 任务)
    ↓
判断线程是否已创建?
    ├─ 否 → startThread()
    │        ↓
    │   executor.execute(new Runnable() {
    │       thread = Thread.currentThread();
    │       NioEventLoop.this.run();  // 启动事件循环
    │   })
    │        ↓
    │   线程创建并启动
    │        ↓
    └─ 是 → 直接添加任务到 taskQueue
         ↓
    任务在事件循环中被执行

11.3 事件循环的运行流程

NioEventLoop.run() {
    for (;;) {  // 无限循环
        
        // 1. 选择策略:是否有任务?
        if (hasTasks()) {
            selectNow();  // 非阻塞 select
        } else {
            select();     // 阻塞 select
        }
        
        // 2. 处理 IO 事件
        processSelectedKeys();
        
        // 3. 处理任务队列中的任务
        runAllTasks();
        
        // 4. 检查是否需要关闭
        if (isShuttingDown()) {
            closeAll();
            if (confirmShutdown()) {
                return;  // 退出循环
            }
        }
    }
}

十二、关键代码片段详解

12.1 线程的延迟创建

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

    // 判断当前线程是否是 EventLoop 线程
    boolean inEventLoop = inEventLoop();
    
    // 添加任务到队列
    addTask(task);

    if (!inEventLoop) {
        // 如果不是 EventLoop 线程,启动线程
        startThread();
        
        // 如果已经关闭,移除任务并拒绝
        if (isShutdown() && removeTask(task)) {
            reject();
        }
    }

    // 如果需要,唤醒线程
    if (!addTaskWakesUp && wakesUpForTask(task)) {
        wakeup(inEventLoop);
    }
}

startThread() 方法:

private void startThread() {
    // 使用 CAS 保证只启动一次
    if (state == ST_NOT_STARTED) {
        if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
            try {
                doStartThread();
            } catch (Throwable cause) {
                STATE_UPDATER.set(this, ST_NOT_STARTED);
                PlatformDependent.throwException(cause);
            }
        }
    }
}

doStartThread() 方法:

private void doStartThread() {
    assert thread == null;
    
    // 使用 ThreadPerTaskExecutor 创建线程
    executor.execute(new Runnable() {
        @Override
        public void run() {
            // 保存线程引用
            thread = Thread.currentThread();
            
            if (interrupted) {
                thread.interrupt();
            }

            boolean success = false;
            updateLastExecutionTime();
            try {
                // 执行事件循环
                SingleThreadEventExecutor.this.run();
                success = true;
            } catch (Throwable t) {
                logger.warn("Unexpected exception from an event executor: ", t);
            } finally {
                // 清理工作
                // ...
            }
        }
    });
}

关键点:

  1. 使用 CAS 保证线程只创建一次
  2. 线程创建后立即执行 run() 方法,进入事件循环
  3. 事件循环是一个无限循环,直到 EventLoop 关闭

12.2 任务队列的处理

// SingleThreadEventExecutor.runAllTasks()
protected boolean runAllTasks(long timeoutNanos) {
    // 1. 从 scheduledTaskQueue 中取出到期的定时任务,放入 taskQueue
    fetchFromScheduledTaskQueue();
    
    // 2. 从 taskQueue 中取出第一个任务
    Runnable task = pollTask();
    if (task == null) {
        afterRunningAllTasks();
        return false;
    }

    // 3. 计算截止时间
    final long deadline = ScheduledFutureTask.nanoTime() + timeoutNanos;
    long runTasks = 0;
    long lastExecutionTime;
    
    // 4. 循环执行任务
    for (;;) {
        // 执行任务
        safeExecute(task);

        runTasks ++;

        // 每执行 64 个任务,检查一次时间
        if ((runTasks & 0x3F) == 0) {
            lastExecutionTime = ScheduledFutureTask.nanoTime();
            if (lastExecutionTime >= deadline) {
                break;  // 超时,退出
            }
        }

        // 取下一个任务
        task = pollTask();
        if (task == null) {
            lastExecutionTime = ScheduledFutureTask.nanoTime();
            break;
        }
    }

    afterRunningAllTasks();
    this.lastExecutionTime = lastExecutionTime;
    return true;
}

关键点:

  1. 支持定时任务(scheduledTaskQueue)
  2. 支持普通任务(taskQueue)
  3. 通过 timeoutNanos 限制执行时间,避免任务执行时间过长
  4. 每执行 64 个任务检查一次时间,这是一个性能优化

12.3 IO 事件的处理

// NioEventLoop.processSelectedKeys()
private void processSelectedKeys() {
    if (selectedKeys != null) {
        // 使用优化的 SelectedKeys
        processSelectedKeysOptimized();
    } else {
        // 使用普通的 SelectedKeys
        processSelectedKeysPlain(selector.selectedKeys());
    }
}

优化版本的处理:

private void processSelectedKeysOptimized() {
    for (int i = 0; i < selectedKeys.size; ++i) {
        final SelectionKey k = selectedKeys.keys[i];
        // 清空数组位置,帮助 GC
        selectedKeys.keys[i] = null;

        // 获取 attachment,这是我们注册时附加的 NioChannel
        final Object a = k.attachment();

        if (a instanceof AbstractNioChannel) {
            // 处理这个 Channel 的事件
            processSelectedKey(k, (AbstractNioChannel) a);
        } else {
            @SuppressWarnings("unchecked")
            NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;
            processSelectedKey(k, task);
        }

        // 检查是否需要再次 select
        if (needsToSelectAgain) {
            selectedKeys.reset(i + 1);
            selectAgain();
            i = -1;
        }
    }
}

处理单个 Key:

private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
    final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
    
    // 检查 Key 是否有效
    if (!k.isValid()) {
        unsafe.close(unsafe.voidPromise());
        return;
    }

    try {
        int readyOps = k.readyOps();
        
        // 处理 OP_CONNECT 事件
        if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
            int ops = k.interestOps();
            ops &= ~SelectionKey.OP_CONNECT;
            k.interestOps(ops);
            unsafe.finishConnect();
        }

        // 处理 OP_WRITE 事件
        if ((readyOps & SelectionKey.OP_WRITE) != 0) {
            ch.unsafe().forceFlush();
        }

        // 处理 OP_READ 或 OP_ACCEPT 事件
        if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
            unsafe.read();
        }
    } catch (CancelledKeyException ignored) {
        unsafe.close(unsafe.voidPromise());
    }
}

关键点:

  1. 使用优化的数组遍历,比 HashSet 的迭代器快
  2. 处理完后清空数组位置,帮助 GC
  3. 根据不同的事件类型,调用不同的处理方法
  4. 异常处理:如果 Key 被取消,关闭 Channel

十五、总结与回顾

15.1 核心知识点总结

1. NioEventLoopGroup 的本质
  • 是 Netty 的线程池实现
  • 管理多个 NioEventLoop 实例
  • 通过 Chooser 实现负载均衡
2. NioEventLoop 的本质
  • 是单线程的事件循环
  • 包含一个 Thread、一个 Selector、一个 taskQueue
  • 负责处理 IO 事件和非 IO 任务
3. 关键设计理念
  • 单线程模型:避免锁竞争,保证顺序性
  • Reactor 模式:一个线程管理多个连接
  • 延迟创建:线程在第一次使用时才创建
  • Channel 绑定:一个 Channel 只绑定到一个 EventLoop
4. 核心参数
  • nThreads:线程数,默认 CPU 核心数 * 2
  • ioRatio:IO 和非 IO 任务的时间比例,默认 50
  • maxPendingTasks:任务队列容量,默认 16
5. 性能优化
  • 优化 Selector 的 selectedKeys 数据结构
  • 解决 JDK 的 epoll bug
  • 使用 MPSC 队列
  • 支持零拷贝

15.3 关键代码位置

核心类:
- io.netty.channel.nio.NioEventLoopGroup
- io.netty.channel.nio.NioEventLoop
- io.netty.channel.MultithreadEventLoopGroup
- io.netty.util.concurrent.MultithreadEventExecutorGroup
- io.netty.util.concurrent.SingleThreadEventExecutor

关键方法:
- NioEventLoopGroup 构造方法
- MultithreadEventExecutorGroup.newChild()
- SingleThreadEventExecutor.execute()
- SingleThreadEventExecutor.startThread()
- NioEventLoop.run()
- NioEventLoop.processSelectedKeys()
- NioEventLoop.runAllTasks()

15.4 延伸阅读

  1. Reactor 模式:理解事件驱动的设计模式
  2. Java NIO:理解 Selector、Channel、Buffer 的使用
  3. 线程模型:对比不同的线程模型(单线程、多线程、主从 Reactor)
  4. 无锁编程:理解 CAS、MPSC 队列等无锁技术

附录:完整的类图关系

EventExecutorGroup (接口)
    ↑
EventLoopGroup (接口)
    ↑
AbstractEventExecutorGroup (抽象类)
    ↑
MultithreadEventExecutorGroup (抽象类)
    ├── children: EventExecutor[]  // 核心数组
    ├── chooser: EventExecutorChooser  // 选择器
    └── terminationFuture: Promise  // 终止 Future
    ↑
MultithreadEventLoopGroup (抽象类)
    └── DEFAULT_EVENT_LOOP_THREADS  // 默认线程数
    ↑
NioEventLoopGroup (实现类)
    └── newChild() 方法  // 创建 NioEventLoop

---

EventExecutor (接口)
    ↑
EventLoop (接口)
    ↑
AbstractEventExecutor (抽象类)
    ↑
SingleThreadEventExecutor (抽象类)
    ├── thread: Thread  // 工作线程
    ├── executor: Executor  // 线程创建器
    ├── taskQueue: Queue<Runnable>  // 任务队列
    └── state: int  // 状态
    ↑
SingleThreadEventLoop (抽象类)
    └── tailTasks: Queue<Runnable>  // 尾部任务队列
    ↑
NioEventLoop (实现类)
    ├── selector: Selector  // NIO Selector
    ├── provider: SelectorProvider  // Selector 提供者
    ├── selectStrategy: SelectStrategy  // 选择策略
    └── ioRatio: int  // IO 比例

java 对接工行聚富通H5聚合支付接口 阅读详情

相关推荐

华为昇腾 910B 实战:DeepSeek-R1 蒸馏模型高效部署与性能调优全解析

本文详细解析了在华为昇腾910B硬件平台上高效部署DeepSeek-R1蒸馏系列模型(14B/32B版本)的完整实战流程。内容涵盖从MindIE环境搭建、镜像获取、模型准备,到服务配置、内存参数调优、性能测试及常见问题排查,为开发者提供了基于昇腾910B进行大模型部署与优化的全链路指南。

weixin_28235513的博客 211

NioEventLoopGroup初始化

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

weixin_30606669的博客 481

VirtualBox虚拟机拖放文件总失败?手把手教你配置双向拖放与共享文件夹(Ubuntu版)

本文详细指导如何在VirtualBox的Ubuntu虚拟机中配置高效的数据交换方案。核心是安装VirtualBox Guest Additions,并在此基础上开启双向拖放与共享粘贴板功能,同时建立稳定的共享文件夹,彻底解决主机与虚拟机间文件传输失败的问题,构建无缝的跨系统工作环境。

weixin_29245767的博客 232

Netty中NioEventLoopGroup介绍

Netty中的核心类之一的:NioEventLoopGroup

小飞侠的博客 2413

实测有效!易灵思FPGA工程如何正确配置Efinity+Modelsim仿真环境

本文详细介绍了易灵思FPGA工程中如何高效配置Efinity与Modelsim联合仿真环境,包括软件版本匹配、系统环境变量设置、工程文件结构优化及仿真脚本深度优化等实战经验。通过实测数据验证,该方案可显著提升仿真效率,适用于不同规模的设计验证,帮助工程师快速搭建稳定高效的联仿环境。

m2n3b4v5c6的博客 405

基础的pdf病毒木马

基础的pdf病毒木马 环境: 攻击机:Kali 目标操作系统:Windows 10或Windows 7 (关闭防火墙和安全软件) 目标软件:Adobe Reader 8.1.2 msf框架搜索:adobe-pdf 1.打开msfconsole 2.搜索 adobe_pdf模块 3.加载攻击模块并设置payload 4.运行生成pdf 5.将pdf拖入到win10 6.打开msf,加...

小小猪的博客 4624

Netty系列-1 NioEventLoopGroup和NioEventLoop介绍

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

shengyu 2175

孤读paper——《GhostNet:More Features from Cheap Operations》

《GhostNet:More Features from Cheap Operations》   发现一个点并解决就是一篇CVPR,该文章主要发现了优秀的网络的特点是feature map提取过程中的冗余性,这种冗余性体现在很多成对的feature map间很像,就好像彼此的“ghost”,而这种特征冗余性对于理解图像来说还是必要的,所以文章把feature map分为两种,一种是本质特征,一...

雄关漫道真如铁 而今迈步从头越 5151

NioEventLoopGroup

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

qq_32259579的博客 883

yanshee 机器人全流程指南

2.点击yanshee app右上角根据提示操作 3.当手机显示成功连接 ,按下机器人胸前按钮说出“ip地址”4.根据机器人播报的ip地址加上:8888使用浏览器访问,你就会看到 jupyterd的界面,里面可以新建文件也可以改他存在的文件。我们使了yanshee机器人,这个是面向K12、中高职、高校学生推出的开源人形机器人教育平台,应用于课程教学、竞赛、科研活动等场景。我们接下来可以根据这些apl做许多好玩的,比如控制他运动,跳舞唱歌,it`s easy。注意电脑,手机,机器人必须连同一个网。

qq_44827929的博客 7614

基于STM32设计的数字电子秤

当前项目是采用采用STM32+称重模块+OLED实现了简单的电子秤项目,称重模块上采用24位的ADC芯片,精度较高。实现了称重,校准、去皮等功能。

1万+

Netty源码分析篇:NioEventLoopGroup分析

Netty源码分析篇:NioEventLoopGroup分析

java_rutu的博客 666

深度学习之目标检测--Pytorch实战

只需要能看懂python代码,就能最快入门深度学习---目标检测。目标检测简单的玩玩儿还行,模型调优,调参,还需要一定的数学功底。通过代码来实现卷积,池化,非线性激活,正则化,归一化,能让人减少对大量数学公式的敬畏,手写神经网络也是考研复试中上机考试的压轴题,掌握搭建神经网络和如何训练模型是需要掌握的基础的

需要远程指导仿真实验、代码有问题的,请后台私信或者关注公众号 1万+

Netty源码深度解析

最后做一个小的总结,下图是我在网上,充分说明了Netty框架的运行模式,它是基于Reactor模型的主从架构:需要创建两个线程组EventLoopGroup,即bossGroup和workerGroup,一般bossGroup设置的线程组中线程的数量为1(也可以设置>1,如果这样设置的话,就需要绑定其他的端口,设置几个,绑定几个端口),workerGroup设置的线程组是多个,不设置默认创建的线程数量为 CPU核心数×2。今天,聊一聊Netty源码。因此,Netty使用。

weixin_41338970的博客 2282

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

netty深度解析

这一章是 Netty 源码分析系列 的第一章, 我打算在这一章中, 展示一下 Netty 的客户端和服务端的初始化和启动的流程, 给读者一个对 Netty 源码有一个大致的框架上的认识, 而不会深入每个功能模块. 本章会从 Bootstrap/ServerBootstrap 类 入手, 分析 Netty 程序的初始化和启动的流程. Bootstrap Bootstrap 是 Netty 提供的...

qq_33849244的博客 312

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Netty源码分析---ThreadPerTaskExecutor与线程创建详解

Netty源码分析---ThreadPerTaskExecutor与线程创建详解

java_rutu的博客 167

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

netty源码分析(十五)Channel注册流程深度解读

前边的介绍是netty对一些组件初始化的过程,接下来是第二部分,注册,还是之前的initAndRegister方法: final ChannelFuture initAndRegister() { Channel channel = null; ...略 channel = channelFactory.newChannel();

wzq6578702的专栏 757

Netty源码分析第1章(Netty启动流程)---->第1节: 服务端初始化

Netty源码分析第1章(Netty启动流程)---->第1节: 服务端初始化 Netty源码分析第一章: Server启动流程 概述: 本章主要讲解server启动的关键步骤, 读者只需要了解server启动的大概逻辑, 知道关键的步骤在哪个类执行即可, 并不需要了解每一步的运作机制, 之后会对每个模块进行深...

weixin_30555753的博客 136

2.4 java面试题:Netty

Netty 是一个,用于快速开发高性能、高可靠性的网络 IO 程序。它在 Java 领域中的地位,就像“网络编程的 Spring”,几乎统治了所有需要自定义协议的中间件和分布式组件。老练的 Java 工程师说 Netty,不仅要讲“是什么”,还要讲清它,以及。

你是人间四月天 220

Netty03-核心组件NioEventLoopGroup解读

可以看到NioEventLoopGroup继承了MultithreadEventExecutorGroup并且实现了EventLoopGroup接口,而这两个类被ExecutorService修饰,所以NioEventLoopGroup实际上是一个线程池,池中的对象其实就是单个的NioEventLoop。

weixin_43747389的博客 974

Netty NioEventLoopGroup 详解及详细源码展示

Netty的NioEventLoopGroup是实现高性能网络编程的核心组件,它通过线程池化的事件循环机制处理海量并发连接。该组件采用自动扩容设计,默认创建2倍CPU核心数的事件循环,并使用Round-Robin策略分配任务。源码分析显示其核心类结构包括MultithreadEventExecutorGroup和NioEventLoop等关键类,实现了通道注册、任务调度及优雅关闭等功能。优化技术包括线程数自动调优、Selector优化等,确保了高吞吐量和低延迟。

csdn_tom_168的博客 1488

Netty Review - NioEventLoopGroup源码解析

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

小工匠 8274

Netty源码分析——NioEventLoopGroup & NioEventLoop

目录   1、NioEventLoopGroup 1.1 类图 1.2 初始化 1.创建线程执行器 2.创建EventLoop,并存储到EventExecutor类型的数组中 3.创建线程选择器 2、NioEventLoop 2.1 类图 2.2 selector 2.3 run 1.轮询io事件 2.处理轮询到的key 3.执行任务队列中的task 1、NioEve...

weixin_43599368的博客 800

Netty核心类之NioEventLoopGroup

NioEventLoopGroup是一个线程池,负责管理和调度一组NioEventLoop线程。

qq_49739667的博客 708

吃透Netty源码系列一之NioEventLoopGroup

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

王伟王胖胖的博客 5662

2、NioEventLoopGroup概览

下面是一个简单的服务器程序 public class TimeServer { public void bind(int port) { //NIO线程组,Reactor线程组,一个用于接受客户端的请求,另一个用于进行SocketChannel的操作 EventLoopGroup bossGroup = new NioEventLoopGroup(); 。。。。。。 }...

zhen_hong的博客 854
上一篇: Netty源码分析---inEventLoop方法详解
下一篇: Netty源码分析---NioEventLoop的run方法详解
不早睡不改名@
博客等级 码龄5年 536粉丝 306原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值