Netty Review - NioEventLoopGroup源码解析

文章目录

  • 概述
  • 类继承关系
  • 源码分析
  • 小结

在这里插入图片描述

在这里插入图片描述


概述

在这里插入图片描述

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

这段代码是在使用Netty框架时常见的用法,用于创建两个不同的EventLoopGroup实例,一个用于处理连接请求(通常称为bossGroup),另一个用于处理连接后的数据流(通常称为workerGroup)。

NioEventLoopGroup是Netty中用于处理NIO事件的EventLoopGroup的实现之一。在Netty中,事件循环(EventLoop)是Netty的核心,负责处理各种事件,比如接收连接、读取数据、写入数据等。

其主要功能和构造函数参数的含义:

  1. 构造函数参数说明:

    • 第一个构造函数参数表示创建的EventLoop的数量。对于bossGroup,它通常设置为1,因为它主要用于处理连接请求,而不是处理连接后的数据流。对于workerGroup,通常不设置数量,因为它会根据系统的CPU核心数量自动创建相应数量的EventLoop。
  2. 在构造函数中,NioEventLoopGroup会创建一组NioEventLoop实例。NioEventLoop是Netty中基于NIO的事件循环实现,它负责处理事件的派发和执行。

  3. NioEventLoopGroup的实现中,通常会创建一个或多个线程来执行事件循环中的任务。这些线程会不断地轮询注册在其上的Channel,处理各种事件。

  4. 对于bossGroup和workerGroup,它们分别负责处理不同类型的事件,bossGroup主要处理连接请求,而workerGroup主要处理连接后的数据流。

总的来说,NioEventLoopGroup的源码实现涉及到底层的NIO编程和多线程处理,它提供了一个高效的事件处理机制,使得Netty能够处理大量并发连接和数据流。


类继承关系

在这里插入图片描述


源码分析

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

NioEventLoopGroup类的构造函数,用于创建一个新的NioEventLoopGroup实例。

public NioEventLoopGroup(int nThreads) {this(nThreads, (Executor) null);
}

这个构造函数接受一个参数nThreads,表示要创建的EventLoop的数量。然后调用了另一个构造函数this(nThreads, (Executor) null)

在这个构造函数中,nThreads表示要创建的EventLoop的数量,通常情况下会根据CPU核心数来确定。参数(Executor) null表示没有指定额外的Executor,这意味着EventLoopGroup会使用默认的线程工厂来创建线程。

总的来说,这个构造函数的作用是根据指定的线程数量创建一个新的NioEventLoopGroup实例,并使用默认的线程工厂来创建线程。


继续

  public NioEventLoopGroup(int nThreads, Executor executor) {this(nThreads, executor, SelectorProvider.provider());}

这段代码是NioEventLoopGroup类的构造函数的另一个重载版本,接受三个参数:nThreadsexecutorSelectorProvider.provider()

这个构造函数接受三个参数:

  1. nThreads表示要创建的EventLoop的数量。
  2. executor表示一个可选的外部Executor,用于执行EventLoop中的任务。如果传入null,则会使用默认的线程工厂来创建线程。
  3. SelectorProvider.provider()返回一个默认的SelectorProvider,用于创建Selector实例。

然后,这个构造函数调用了另一个构造函数this(nThreads, executor, SelectorProvider.provider()),将这三个参数传递给它。

这个构造函数的作用是根据指定的线程数量创建一个新的NioEventLoopGroup实例,并允许传入一个可选的Executor,以及一个SelectorProvider,用于创建Selector实例。


继续

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

这段代码是NioEventLoopGroup类的构造函数的另一个重载版本,接受四个参数:nThreadsexecutorselectorProviderDefaultSelectStrategyFactory.INSTANCE

这个构造函数接受四个参数:

  1. nThreads表示要创建的EventLoop的数量。
  2. executor表示一个可选的外部Executor,用于执行EventLoop中的任务。如果传入null,则会使用默认的线程工厂来创建线程。
  3. selectorProvider表示一个SelectorProvider,用于创建Selector实例。
  4. DefaultSelectStrategyFactory.INSTANCE是一个默认的Select策略工厂实例,用于创建Select策略。

然后,这个构造函数调用了另一个构造函数this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE),将这四个参数传递给它。

这个构造函数的作用是根据指定的线程数量创建一个新的NioEventLoopGroup实例,并允许传入一个可选的Executor、SelectorProvider,以及一个默认的Select策略工厂实例。


继续

public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,final SelectStrategyFactory selectStrategyFactory) {super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}

这段代码是NioEventLoopGroup类的构造函数的最终版本,接受五个参数:nThreadsexecutorselectorProviderselectStrategyFactoryRejectedExecutionHandlers.reject()

这个构造函数调用了父类构造函数super(),传递了五个参数:

  1. nThreads表示要创建的EventLoop的数量。
  2. executor表示一个可选的外部Executor,用于执行EventLoop中的任务。如果传入null,则会使用默认的线程工厂来创建线程。
  3. selectorProvider表示一个SelectorProvider,用于创建Selector实例。
  4. selectStrategyFactory表示一个Select策略工厂,用于创建Select策略。
  5. RejectedExecutionHandlers.reject()是一个拒绝执行处理器,用于处理任务提交被拒绝的情况。

这个构造函数的作用是根据指定的参数创建一个新的NioEventLoopGroup实例,并设置Executor、SelectorProvider、Select策略工厂和拒绝执行处理器。


继续

protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}

这段代码是MultithreadEventLoopGroup类的构造函数,它是MultithreadEventExecutorGroup类的子类。让我们详细解释这段代码的实现:

这个构造函数通过调用父类构造函数super()来创建一个新的MultithreadEventLoopGroup实例,它接受三个参数:

  1. nThreads表示要创建的EventLoop的数量,如果传入的值为0,则使用默认值DEFAULT_EVENT_LOOP_THREADS
  2. executor表示一个可选的外部Executor,用于执行EventLoop中的任务。如果传入null,则会使用默认的线程工厂来创建线程。
  3. args表示可变参数,用于传递额外的参数给父类构造函数。

在这个构造函数中,首先通过三元运算符判断nThreads是否为0,如果是,则使用默认值DEFAULT_EVENT_LOOP_THREADS,否则使用传入的值。然后调用父类构造函数,传递这三个参数。


DEFAULT_EVENT_LOOP_THREADS

private static final int DEFAULT_EVENT_LOOP_THREADS;static {// 获取系统属性"io.netty.eventLoopThreads",如果未设置,则使用默认值为可用处理器数的两倍DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));// 如果日志级别为DEBUG,则输出默认的EventLoop线程数if (logger.isDebugEnabled()) {logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);}
}

这段代码是一个静态代码块,用于初始化DEFAULT_EVENT_LOOP_THREADS这个静态常量。

这个静态代码块主要做了两件事情:

  1. 通过SystemPropertyUtil.getInt()方法获取系统属性"io.netty.eventLoopThreads"的值,如果未设置,则使用默认值为可用处理器数的两倍。
  2. 如果日志级别为DEBUG,则通过日志记录框架输出默认的EventLoop线程数。

这个静态代码块的作用是在类加载时初始化DEFAULT_EVENT_LOOP_THREADS这个静态常量,并根据系统属性设置默认的EventLoop线程数。

总的来说,这个构造函数的作用是根据指定的参数创建一个新的MultithreadEventLoopGroup实例,并设置EventLoop的数量和Executor。


继续

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

这段代码是MultithreadEventExecutorGroup类的受保护构造函数,用于创建一个新的MultithreadEventExecutorGroup实例。

这个构造函数接受三个参数:

  1. nThreads表示要创建的线程数。
  2. executor表示一个可选的外部Executor,用于执行任务。如果传入null,则会使用默认的线程工厂来创建线程。
  3. args表示可变参数,用于传递额外的参数给子类的newChild()方法。

在这个构造函数中,调用了另一个构造函数this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args),将这三个参数传递给它,并传递了一个默认的EventExecutor选择器工厂实例DefaultEventExecutorChooserFactory.INSTANCE

这个构造函数的作用是根据指定的参数创建一个新的MultithreadEventExecutorGroup实例,并使用默认的EventExecutor选择器工厂。


继续

这段代码是MultithreadEventExecutorGroup类的受保护构造函数的具体实现,用于创建一个新的MultithreadEventExecutorGroup实例。

请看注释

protected MultithreadEventExecutorGroup(int nThreads, Executor executor,EventExecutorChooserFactory chooserFactory, Object... args) {if (nThreads <= 0) {throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));}// 如果传入的Executor为null,则使用默认的ThreadPerTaskExecutor,并创建一个新的线程工厂if (executor == null) {executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());}// 初始化children数组,用于存储创建的EventExecutor实例children = new EventExecutor[nThreads];// 循环创建nThreads个EventExecutor实例for (int i = 0; i < nThreads; i ++) {boolean success = false;try {// 调用newChild方法创建EventExecutor实例,并将其存储到children数组中children[i] = newChild(executor, args);success = true;} catch (Exception e) {// 在创建EventExecutor实例时发生异常,抛出IllegalStateException异常throw new IllegalStateException("failed to create a child event loop", e);} finally {// 如果创建EventExecutor实例失败,则关闭已创建的实例if (!success) {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;}}}}}// 根据chooserFactory创建一个EventExecutor选择器chooser = chooserFactory.newChooser(children);// 创建一个监听器,用于监听所有EventExecutor实例的终止事件final FutureListener<Object> terminationListener = new FutureListener<Object>() {@Overridepublic void operationComplete(Future<Object> future) throws Exception {if (terminatedChildren.incrementAndGet() == children.length) {terminationFuture.setSuccess(null);}}};// 添加终止事件监听器到每个EventExecutor实例的terminationFuture上for (EventExecutor e: children) {e.terminationFuture().addListener(terminationListener);}// 将children数组转换为不可修改的集合Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);Collections.addAll(childrenSet, children);readonlyChildren = Collections.unmodifiableSet(childrenSet);
}

这个构造函数的作用是根据指定的参数创建一个新的MultithreadEventExecutorGroup实例,并初始化一组EventExecutor实例。

如果创建EventExecutor实例失败,则会关闭已创建的实例,并等待它们终止。

最后,创建一个监听器用于监听所有EventExecutor实例的终止事件,并将children数组转换为不可修改的集合。


重点关注 children[i] = newChild(executor, args);

在这里插入图片描述

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

这段代码是MultithreadEventLoopGroup类中的一个重要方法newChild()的实现,它用于创建新的EventLoop实例。

@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {// 从参数数组中获取需要的参数,包括SelectorProvider、SelectStrategyFactory和RejectedExecutionHandlerSelectorProvider selectorProvider = (SelectorProvider) args[0];SelectStrategyFactory selectStrategyFactory = (SelectStrategyFactory) args[1];RejectedExecutionHandler rejectedExecutionHandler = (RejectedExecutionHandler) args[2];// 调用NioEventLoop的构造函数创建一个新的NioEventLoop实例,并返回return new NioEventLoop(this, executor, selectorProvider, selectStrategyFactory.newSelectStrategy(), rejectedExecutionHandler);
}

这个方法的作用是根据给定的参数创建一个新的EventLoop实例。它首先从参数数组中获取所需的参数,包括SelectorProvider、SelectStrategyFactory和RejectedExecutionHandler,然后调用NioEventLoop的构造函数创建一个新的NioEventLoop实例,并将这些参数传递给它。

总的来说,newChild()方法的作用是创建一个新的EventLoop实例,并返回该实例。在MultithreadEventLoopGroup中,每个EventLoop实例都负责处理一部分任务。


new NioEventLoop(this, executor, selectorProvider, selectStrategyFactory.newSelectStrategy(), rejectedExecutionHandler)

这段代码是NioEventLoop类的构造函数,用于创建一个新的NioEventLoop实例。

让我们逐步解释这段代码的实现:

NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {// 调用父类SingleThreadEventExecutor的构造函数创建一个新的实例super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);// 检查selectorProvider和selectStrategy是否为null,如果是则抛出NullPointerExceptionif (selectorProvider == null) {throw new NullPointerException("selectorProvider");}if (strategy == null) {throw new NullPointerException("selectStrategy");}// 初始化成员变量provider为传入的selectorProviderprovider = selectorProvider;// 调用openSelector()方法打开一个新的Selector,并将返回的SelectorTuple中的selector和unwrappedSelector分别赋值给成员变量selector和unwrappedSelectorfinal SelectorTuple selectorTuple = openSelector();selector = selectorTuple.selector;unwrappedSelector = selectorTuple.unwrappedSelector;// 初始化成员变量selectStrategy为传入的strategyselectStrategy = strategy;
}

这个构造函数的作用是初始化NioEventLoop实例的成员变量。

它首先调用父类SingleThreadEventExecutor的构造函数,然后检查传入的selectorProvider和selectStrategy是否为null,如果是则抛出NullPointerException。

接着,将传入的selectorProvider赋值给成员变量provider,并调用openSelector()方法打开一个新的Selector,并将返回的SelectorTuple中的selector和unwrappedSelector分别赋值给成员变量selector和unwrappedSelector。

最后,将传入的strategy赋值给成员变量selectStrategy。

总的来说,这个构造函数的作用是初始化NioEventLoop实例的成员变量,包括selector、unwrappedSelector、provider和selectStrategy


重点关注: super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);final SelectorTuple selectorTuple = openSelector();

super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler)

protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor,boolean addTaskWakesUp, int maxPendingTasks,RejectedExecutionHandler rejectedExecutionHandler) {// 调用父类SingleThreadEventExecutor的构造函数创建一个新的实例super(parent, executor, addTaskWakesUp, maxPendingTasks, rejectedExecutionHandler);// 初始化tailTasks,使用newTaskQueue方法创建一个新的任务队列tailTasks = newTaskQueue(maxPendingTasks);
}

这段代码是SingleThreadEventLoop类的受保护构造函数的实现,用于创建一个新的SingleThreadEventLoop实例。

这个构造函数的作用是创建一个新的SingleThreadEventLoop实例,并初始化它的成员变量。首先调用父类SingleThreadEventExecutor的构造函数,然后使用newTaskQueue方法创建一个新的任务队列tailTasks,并将其赋值给成员变量tailTasks。

总的来说,这个构造函数的作用是初始化SingleThreadEventLoop实例的成员变量,并设置其父类、执行器、任务唤醒标志、最大挂起任务数和拒绝执行处理器

super(parent, executor, addTaskWakesUp, maxPendingTasks, rejectedExecutionHandler)

这段代码是SingleThreadEventExecutor类的受保护构造函数的实现,用于创建一个新的SingleThreadEventExecutor实例。让我们逐步解释这段代码的实现:

protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,boolean addTaskWakesUp, int maxPendingTasks,RejectedExecutionHandler rejectedHandler) {// 调用父类构造函数,设置父类EventExecutorGroupsuper(parent);// 设置是否唤醒线程的标志this.addTaskWakesUp = addTaskWakesUp;// 设置最大挂起任务数,确保最小为16this.maxPendingTasks = Math.max(16, maxPendingTasks);// 应用ThreadExecutorMap,确保executor为非空this.executor = ThreadExecutorMap.apply(executor, this);// 初始化任务队列taskQueue = newTaskQueue(this.maxPendingTasks);// 设置拒绝执行处理器rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}

这个构造函数的作用是创建一个新的SingleThreadEventExecutor实例,并设置其成员变量。它首先调用父类的构造函数,设置父类EventExecutorGroup。然后,根据传入的参数设置是否唤醒线程的标志addTaskWakesUp、最大挂起任务数maxPendingTasks、执行器executor以及拒绝执行处理器rejectedExecutionHandler。

总的来说,这个构造函数的作用是初始化SingleThreadEventExecutor实例的成员变量,并设置其父类、执行器、唤醒线程标志、最大挂起任务数和拒绝执行处理器。

tailTasks = newTaskQueue(maxPendingTasks);

这段代码是SingleThreadEventExecutor类中的一个方法newTaskQueue()的实现。这个方法用于创建一个任务队列,用于存储待执行的任务。

让我们逐步解释这段代码的实现:

 
protected Queue<Runnable> newTaskQueue(int maxPendingTasks) {// 创建一个LinkedBlockingQueue实例作为任务队列,并设置最大容量为maxPendingTasksreturn new LinkedBlockingQueue<Runnable>(maxPendingTasks);
}

这个方法的作用是创建一个新的任务队列,用于存储待执行的任务。默认实现使用了LinkedBlockingQueue,它是一个基于链表的阻塞队列,具有无界的容量,但可以通过maxPendingTasks参数设置最大容量。如果子类重写这个方法,并且不会对队列执行阻塞调用,可以选择返回一个不支持阻塞操作的更高性能的实现。

总的来说,newTaskQueue()方法的作用是创建一个任务队列,并返回该队列的实例。


final SelectorTuple selectorTuple = openSelector()

这段代码是NioEventLoop类中的一个方法openSelector()的实现,用于打开一个新的Selector。让我们逐步解释这段代码的实现:

private SelectorTuple openSelector() {// 声明一个未包装的Selectorfinal Selector unwrappedSelector;try {// 尝试打开一个新的SelectorunwrappedSelector = provider.openSelector();} catch (IOException e) {// 打开Selector失败,抛出异常throw new ChannelException("failed to open a new selector", e);}// 如果禁用了选择键集合优化,则返回一个包含未包装的Selector的SelectorTupleif (DISABLE_KEY_SET_OPTIMIZATION) {return new SelectorTuple(unwrappedSelector);}// 尝试获取SelectorImpl类Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {@Overridepublic Object run() {try {return Class.forName("sun.nio.ch.SelectorImpl",false,PlatformDependent.getSystemClassLoader());} catch (Throwable cause) {return cause;}}});// 如果没有获取到类或者当前的Selector实现不是我们要的实现,则返回一个包含未包装的Selector的SelectorTupleif (!(maybeSelectorImplClass instanceof Class) ||!((Class<?>) maybeSelectorImplClass).isAssignableFrom(unwrappedSelector.getClass())) {if (maybeSelectorImplClass instanceof Throwable) {Throwable t = (Throwable) maybeSelectorImplClass;logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, t);}return new SelectorTuple(unwrappedSelector);}// 获取到了SelectorImpl类,尝试使用Unsafe替换SelectionKeySetfinal Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();// 使用反射设置Selector的selectedKeys和publicSelectedKeys字段为选定的键集Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {@Overridepublic Object run() {try {// 获取selectedKeys和publicSelectedKeys字段Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");// 如果当前Java版本大于等于9并且具有Unsafe支持,则尝试使用Unsafe替换SelectionKeySetif (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) {// 使用Unsafe替换SelectionKeySetlong selectedKeysFieldOffset = PlatformDependent.objectFieldOffset(selectedKeysField);long publicSelectedKeysFieldOffset =PlatformDependent.objectFieldOffset(publicSelectedKeysField);if (selectedKeysFieldOffset != -1 && publicSelectedKeysFieldOffset != -1) {PlatformDependent.putObject(unwrappedSelector, selectedKeysFieldOffset, selectedKeySet);PlatformDependent.putObject(unwrappedSelector, publicSelectedKeysFieldOffset, selectedKeySet);return null;}// 无法检索偏移量,尝试反射作为最后的手段。}// 尝试设置字段的访问权限Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField, true);if (cause != null) {return cause;}cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField, true);if (cause != null) {return cause;}// 设置选定的键集到Selector的selectedKeys和publicSelectedKeys字段selectedKeysField.set(unwrappedSelector, selectedKeySet);publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);return null;} catch (NoSuchFieldException e) {return e;} catch (IllegalAccessException e) {return e;}}});// 如果出现异常,则返回一个包含未包装的Selector的SelectorTupleif (maybeException instanceof Exception) {selectedKeys = null;Exception e = (Exception) maybeException;logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, e);return new SelectorTuple(unwrappedSelector);}// 成功设置选定的键集,记录日志并返回一个包含未包装的Selector和SelectedSelectionKeySetSelector的SelectorTupleselectedKeys = selectedKeySet;logger.trace("instrumented a special java.util.Set into: {}", unwrappedSelector);return new SelectorTuple(unwrappedSelector,new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
}

这个方法的作用是打开一个新的Selector,并尝试优化其内部的SelectionKey集合。

首先,它尝试直接打开一个新的Selector,如果失败,则抛出异常。

然后,它检查是否禁用了选择键集合优化。如果没有禁用,则尝试获取sun.nio.ch.SelectorImpl类,并验证当前Selector的实现是否与获取的类兼容。如果兼容,则尝试使用Unsafe替换SelectionKeySet以提高性能。

最后,返回一个包含未包装的Selector和可能的SelectedSelectionKeySetSelector的SelectorTuple。


小结

NioEventLoopGroup是Netty中用于处理NIO事件的事件循环组。

下面我们总结下NioEventLoopGroup源码:

  1. 构造函数:NioEventLoopGroup类提供了多个构造函数,用于创建实例。这些构造函数允许指定线程数量、执行器、选择器提供者和选择策略工厂等参数。构造函数内部会调用父类MultithreadEventLoopGroup的构造函数,并设置相关参数。

  2. 多线程事件循环组:NioEventLoopGroup继承自MultithreadEventLoopGroup类,用于管理多个NioEventLoop实例。它负责创建和管理一组NioEventLoop线程,每个线程处理一个Selector的事件循环。

  3. 打开新的Selector:NioEventLoopGroup内部使用openSelector()方法来打开一个新的Selector。该方法尝试优化Selector的内部SelectionKey集合,以提高性能。优化过程包括尝试使用Unsafe替换SelectionKeySet,以更有效地处理SelectionKey的集合。

  4. 任务队列:NioEventLoopGroup内部使用任务队列来存储待执行的任务。默认情况下,它使用LinkedBlockingQueue作为任务队列,但允许子类重写newTaskQueue()方法以选择更高性能的实现。

  5. 执行器和拒绝策略:NioEventLoopGroup使用执行器来执行任务,并提供拒绝执行处理器来处理任务执行失败的情况。

总的来说,NioEventLoopGroup源码实现了一个用于管理和处理NIO事件的多线程事件循环组,它提供了灵活的构造函数和优化的Selector打开机制,以提高整体性能和并发能力。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/465630.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode.145. 二叉树的后序遍历

题目 145. 二叉树的后序遍历 分析 上篇文章我们讲了前序遍历&#xff0c;这道题目是后序遍历。 首先要知道二叉树的后序遍历是什么&#xff1f;【左 右 根】 然后利用递归的思想&#xff0c;就可以得到这道题的答案&#xff0c;任何的递归都可以采用 栈 的结构来实现&#…

华为问界M9:全方位自动驾驶技术解决方案

华为问界M9的自动驾驶技术采用了多种方法来提高驾驶的便利性和安全性。以下是一些关键技术&#xff1a; 智能感知系统&#xff1a;问界M9配备了先进的传感器&#xff0c;包括高清摄像头、毫米波雷达、超声波雷达等&#xff0c;这些传感器可以实时监测车辆周围的环境&#xff0…

Java 使用 Map 集合统计投票人数

Java 使用 Map 集合统计投票人数 package com.zhong.mapdemo.map;import javax.swing.plaf.synth.SynthOptionPaneUI; import java.util.ArrayList; import java.util.HashMap; import java.util.Map;/*** ClassName : MapCountPeopleNumber* Description : 使用 map 统计投票人…

aardio 编辑GUI界面,调用 python 脚本示例

aardio 中调用 python 的方法有两种&#xff0c;py3 和 process.python 模块 py3 模块&#xff1a;如果经常要拿到python返回的值或从aardio中传数据给python去处理&#xff0c;aardio和python的交互比较多的话&#xff0c;可以考虑使用py3模块&#xff0c;缺点是&#xff1a;p…

24个已知403绕过方法的利用脚本

介绍 一个简单的脚本&#xff0c;仅供自用&#xff0c;用于绕过 403 在curl的帮助下使用24个已知的403绕过方法 它还可用于比较各种条件下的响应&#xff0c;如下图所示 用法 ./bypass-403.sh https://example.com admin ./bypass-403.sh website-here path-here 安装 git …

13 年后,我如何用 Go 编写 HTTP 服务(译)

原文&#xff1a;Mat Ryer - 2024.02.09 大约六年前&#xff0c;我写了一篇博客文章&#xff0c;概述了我是如何用 Go 编写 HTTP 服务的&#xff0c;现在我再次告诉你&#xff0c;我是如何写 HTTP 服务的。 那篇原始的文章引发了一些热烈的讨论&#xff0c;这些讨论影响了我今…

JavaScript 遍历文档生成目录结构

JavaScript 遍历文档生成目录结构 要遍历 HTML 文档并生成目录结构&#xff0c;你可以使用 JavaScript 来进行 DOM 操作和遍历。以下是一个简单的示例代码&#xff0c;演示了如何遍历文档中的标题元素&#xff08;例如 <h1>、<h2>、<h3> 等&#xff09;&…

antdpro框架npm install 报错,切换tyarn安装成功。

报错日志 有时间补 当前版本 解决办法 进入工作目录 安装官方推荐的tyarn工具&#xff1a;npm install yarn tyarn -g 进行依赖安装&#xff1a;tyarn 启动项目 &#xff1a;tyarn start 注意&#xff1a; 技术迭代较快&#xff0c;建议查询官网后实践&#xff0c;以上作为…

WSL下如何使用Ubuntu本地部署Vits2.3-Extra-v2:中文特化修复版(新手从0开始部署教程)

环境&#xff1a; 硬&#xff1a; 台式电脑 1.cpu:I5 11代以上 2.内存16G以上 3.硬盘固态500G以上 4.显卡N卡8G显存以上 20系2070以上 本案例英伟达4070 12G 5.网络可连github 软&#xff1a; Win10 专业版 19045以上 WSL2 -Ubuntu22.04 1.bert-Vits2.3 Extra-v2:…

【MySQL进阶之路】好友推荐系统索引设计实战

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…

VMware虚拟机安装openEuler系统(二)(2024)

下面我们进行openEuler系统的一些简单配置。 1. 开启openEuler系统 在VMware Workstation Pro虚拟机软件中找到安装好的openEuler操作系统虚拟机并开启。 等待开启。 2. 安装配置 进入后选择第一个“Install openEuler 20.03-LTS”。 3. 选择系统语言 为虚拟机设置系统语言…

《统计学简易速速上手小册》第5章:回归分析(2024 最新版)

文章目录 5.1 线性回归基础5.1.1 基础知识5.1.2 主要案例&#xff1a;员工薪资预测5.1.3 拓展案例 1&#xff1a;广告支出与销售额关系5.1.4 拓展案例 2&#xff1a;房价与多个因素的关系 5.2 多元回归分析5.2.1 基础知识5.2.2 主要案例&#xff1a;企业收益与多因素关系分析5.…