- 浏览: 980948 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
netty 事件执行器组和事件执行器定义及抽象实现:http://donald-draper.iteye.com/blog/2391257
netty 多线程事件执行器组:http://donald-draper.iteye.com/blog/2391270
netty 多线程事件循环组:http://donald-draper.iteye.com/blog/2391276
netty 抽象调度事件执行器:http://donald-draper.iteye.com/blog/2391379
netty 单线程事件执行器初始化:http://donald-draper.iteye.com/blog/2391895
netty 单线程事件执行器执行任务与graceful方式关闭:http://donald-draper.iteye.com/blog/2392051
netty 单线程事件循环:http://donald-draper.iteye.com/blog/2392067
引言:
前面一篇文章我们看了单线程事件循环,来简单回顾一下:
单线程事件循环SingleThreadEventLoop,继承了单线程事件执行器,实现了事件循环接口,内部一个事件循环任务队列,我们可以把单线程事件循环看为一个简单的事件执行器,单线程事件循环中多了一个通道注册的方法,实际注册工作委托给通道关联的UnSafe。
今天我们来看一下Nio事件循环:
来看一下Nio事件循环中,变量的类型声明:
//IntSupplier
再来看Nio事件循环内部实现:
再来关注一下选择Now操作:
再来看选择策略:
从上面可以看出,Nio事件循环内部有一个取消选择key计数器清理间隔CLEANUP_INTERVAL,用于当取消的选择key达到256个时,重置取消选择key计数器cancelledKeys(int),并重新进行选择操作;选择器自动重构阈值SELECTOR_AUTO_REBUILD_THRESHOLD,默认选择操作发生512次,用于控制当选择器发生多少次选择操作时,重构选择器;选择器状态判断器selectNowSupplier,用于获取Nio事件循环内部选择器的选择操作结果;同时有一个选择器selector,未包装过的选择器unwrappedSelector和一个选择器提供者provider,一个选择key就绪集合selectedKeys(SelectedSelectionKeySet);当选择器的选择操作阻塞时,wakenUp(AtomicBoolean)属性决定是否应该break选择操作过程;一个Nio处理Io事件的时间占比ioRatio(int),默认为50,即IO事件处理时间和其他事件处理时间各占Nio事件循环一半;一个选择策略selectStrategy用于控制选择循环,如果返回结果为-1,则下一步应该阻塞选择操作,如果返回结果为-2,则下一步应该调回IO事件循环,处理IO事件,而不是继续执行选择操作,返回值大于0,表示需要有工作要做,即注册到选择器的选择通道有IO事件就绪。
回到Nio事件循环构造:
先看一下选择器元组SelectorTuple的定义:
选择器元组SelectorTuple实际为选择器和未包装选择器的包装类
再来看打开选择器:
再来看选择器包装类
//SelectedSelectionKeySetSelector
选择器包装类的每次选择操作,首先重置就绪选择key集合,再讲相应的操作委托给内部选择器代理,其他打开唤醒等方法直接委托给内部选择器代理。
从上面可以看出,打开选择器,主要是委托给选择器提供者,如果需要优化选择器的,
在当前线程访问控制选择下,加载选择器实现类,不初始化,如果从系统类加载器加载的选择key实现类不是Class实例,或不是裸选择器类型,不进行选择器key集合优化,及选择器为选择器提供者打开的裸选择器;否则在当前线程相同访问控制权限下,获取系统选择器实现类的,选择器就绪key集合selectedKeysField及其代理publicSelectedKeysField,设置选择器就绪key集合selectedKeysField及其代理publicSelectedKeysField访问控制权限,将系统选择器的就绪key集合selectedKeysField及其代理publicSelectedKeysField设值为
selectedKeySet(SelectedSelectionKeySet),并将选择器selector包装为SelectedSelectionKeySetSelector。
Nio事件循环初始化,主要是将Nio事件循环组和事件执行器及任务拒绝策略传给父类,同时打开一个选择器。
总结:
Nio事件循环内部有一个取消选择key计数器清理间隔CLEANUP_INTERVAL,用于当取消的选择key达到256个时,重置取消选择key计数器cancelledKeys(int),并重新进行选择操作;选择器自动重构阈值SELECTOR_AUTO_REBUILD_THRESHOLD,默认选择操作发生512次,用于控制当选择器发生多少次选择操作时,重构选择器;选择器状态判断器selectNowSupplier,用于获取Nio事件循环内部选择器的选择操作结果;同时有一个选择器selector,未包装过的选择器unwrappedSelector和一个选择器提供者provider,一个选择key就绪集合selectedKeys(SelectedSelectionKeySet);当选择器的选择操作阻塞时,wakenUp(AtomicBoolean)属性决定是否应该break选择操作过程;一个Nio处理Io事件的时间占比ioRatio(int),默认为50,即IO事件处理时间和其他事件处理时间各占Nio事件循环一半;一个选择策略selectStrategy用于控制选择循环,如果返回结果为-1,则下一步应该阻塞选择操作,如果返回结果为-2,则下一步应该调回IO事件循环,处理IO事件,而不是继续执行选择操作,返回值大于0,表示需要有工作要做,即注册到选择器的选择通道有IO事件就绪。
Nio事件循环初始化,主要是将Nio事件循环组和事件执行器及任务拒绝策略传给父类单线程事件循环(单线程事件执行器),同时打开一个选择器。
打开选择器过程,委托给选择器提供者打开一个选择器,如果需要优化选择器的,在当前线程访问控制选择下,加载选择器实现类,不初始化,如果从系统类加载器加载的选择key实现类不是Class实例,或不是裸选择器类型,不进行选择器key集合优化,及选择器为选择器提供者打开的裸选择器;否则在当前线程相同访问控制权限下,获取系统选择器实现类的,选择器就绪key集合selectedKeysField及其代理publicSelectedKeysField,设置选择器就绪key集合selectedKeysField及其代理publicSelectedKeysField访问控制权限,将系统选择器的就绪key集合selectedKeysField及其代理publicSelectedKeysField设值为
selectedKeySet(SelectedSelectionKeySet),并将选择器selector包装为SelectedSelectionKeySetSelector。
附:
下面的选择key集合和反射工具,简单看看就行。
//SelectedSelectionKeySet
//ReflectionUtil
netty 多线程事件执行器组:http://donald-draper.iteye.com/blog/2391270
netty 多线程事件循环组:http://donald-draper.iteye.com/blog/2391276
netty 抽象调度事件执行器:http://donald-draper.iteye.com/blog/2391379
netty 单线程事件执行器初始化:http://donald-draper.iteye.com/blog/2391895
netty 单线程事件执行器执行任务与graceful方式关闭:http://donald-draper.iteye.com/blog/2392051
netty 单线程事件循环:http://donald-draper.iteye.com/blog/2392067
引言:
前面一篇文章我们看了单线程事件循环,来简单回顾一下:
单线程事件循环SingleThreadEventLoop,继承了单线程事件执行器,实现了事件循环接口,内部一个事件循环任务队列,我们可以把单线程事件循环看为一个简单的事件执行器,单线程事件循环中多了一个通道注册的方法,实际注册工作委托给通道关联的UnSafe。
今天我们来看一下Nio事件循环:
package io.netty.channel.nio; import io.netty.channel.Channel; import io.netty.channel.ChannelException; import io.netty.channel.EventLoop; import io.netty.channel.EventLoopException; import io.netty.channel.SelectStrategy; import io.netty.channel.SingleThreadEventLoop; import io.netty.util.IntSupplier; import io.netty.util.concurrent.RejectedExecutionHandler; import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.ReflectionUtil; import io.netty.util.internal.SystemPropertyUtil; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import java.io.IOException; import java.lang.reflect.Field; import java.nio.channels.CancelledKeyException; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.spi.SelectorProvider; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Queue; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; /** * {@link SingleThreadEventLoop} implementation which register the {@link Channel}'s to a * {@link Selector} and so does the multi-plexing of these in the event loop. Nio单线程事件循环,注册关联通道到同一个选择器,以便复用事件循环。 * */ public final class NioEventLoop extends SingleThreadEventLoop { private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioEventLoop.class); //取消选择key计数器,清理间隔,当取消的选择key达到256个时,重置计数器,并重新进行选择操作 private static final int CLEANUP_INTERVAL = 256; // XXX Hard-coded value, but won't need customization. //是否优化选择器key集合,默认为不优化 private static final boolean DISABLE_KEYSET_OPTIMIZATION = SystemPropertyUtil.getBoolean("io.netty.noKeySetOptimization", false); private static final int MIN_PREMATURE_SELECTOR_RETURNS = 3;//最小的选择器重构阈值 private static final int SELECTOR_AUTO_REBUILD_THRESHOLD;//选择器自动重构阈值,默认选择操作发生512次,重构 private final IntSupplier selectNowSupplier = new IntSupplier() { @Override public int get() throws Exception { return selectNow(); } }; //Nio事件循环任务数量Callable private final Callable<Integer> pendingTasksCallable = new Callable<Integer>() { @Override public Integer call() throws Exception { return NioEventLoop.super.pendingTasks(); } }; // Workaround for JDK NIO bug. // // See: // - http://bugs.sun.com/view_bug.do?bug_id=6427854 // - https://github.com/netty/netty/issues/203 static { //获取java的bug等级 final String key = "sun.nio.ch.bugLevel"; final String buglevel = SystemPropertyUtil.get(key); if (buglevel == null) { //如果bug等级为空,则在当前任务线程相同访问控制权限下,设置nio的bug等级为空 try { AccessController.doPrivileged(new PrivilegedAction<Void>() { @Override public Void run() { System.setProperty(key, ""); return null; } }); } catch (final SecurityException e) { logger.debug("Unable to get/set System Property: " + key, e); } } //初始选择器重构阈值 int selectorAutoRebuildThreshold = SystemPropertyUtil.getInt("io.netty.selectorAutoRebuildThreshold", 512); if (selectorAutoRebuildThreshold < MIN_PREMATURE_SELECTOR_RETURNS) { //不需要重构选择器 selectorAutoRebuildThreshold = 0; } SELECTOR_AUTO_REBUILD_THRESHOLD = selectorAutoRebuildThreshold; if (logger.isDebugEnabled()) { logger.debug("-Dio.netty.noKeySetOptimization: {}", DISABLE_KEYSET_OPTIMIZATION); logger.debug("-Dio.netty.selectorAutoRebuildThreshold: {}", SELECTOR_AUTO_REBUILD_THRESHOLD); } } /** * The NIO {@link Selector}. */ private Selector selector;//就绪选择key集合优化后的选择器 private Selector unwrappedSelector;//没有包装过的选择器,即选择器提供者打开的原始选择器 private SelectedSelectionKeySet selectedKeys;//选择key就绪集合 private final SelectorProvider provider;//选择器提供者 /** * Boolean that controls determines if a blocked Selector.select should * break out of its selection process. In our case we use a timeout for * the select method and the select method will block for that time unless * waken up. 当选择器的选择操作阻塞时,wakenUp属性决定是否应该break选择操作过程。在我们的实现中, 我们给选择操作一个超时时间, 除非选择操作被wakeup,否则选择操作达到超时时间,则break选择操作。 */ private final AtomicBoolean wakenUp = new AtomicBoolean(); private final SelectStrategy selectStrategy;//选择策略 private volatile int ioRatio = 50;//Nio处理Io事件的时间占比,以便可以处理器其他非IO事件 private int cancelledKeys;//取消选择key计数器 private boolean needsToSelectAgain;//是否需要重新选择 }
来看一下Nio事件循环中,变量的类型声明:
//IntSupplier
package io.netty.util; /** * Represents a supplier of {@code int}-valued results. 表示一个int值供应者 */ public interface IntSupplier { /** * Gets a result. * * @return a result */ int get() throws Exception; }
再来看Nio事件循环内部实现:
private final IntSupplier selectNowSupplier = new IntSupplier() { //获取选择操作返回值,用于判断注册到当前选择器的选择通道是否有IO事件就绪 @Override public int get() throws Exception { return selectNow(); } };
再来关注一下选择Now操作:
int selectNow() throws IOException { try { //直接委托个Nio事件循环选择器 return selector.selectNow(); } finally { // restore wakeup state if needed //如果选择操作后,需要唤醒等待选择操作的线程,则唤醒 if (wakenUp.get()) { selector.wakeup(); } } }
再来看选择策略:
private final SelectStrategy selectStrategy;//选择策略
package io.netty.channel; import io.netty.util.IntSupplier; /** * Select strategy interface. * * Provides the ability to control the behavior of the select loop. For example a blocking select * operation can be delayed or skipped entirely if there are events to process immediately. 选择策略接口提供了控制选择循环行为的方法。比如,如果有事件需要立刻处理,则可以阻塞选择操作或 完全直接跳过。 */ public interface SelectStrategy { /** * Indicates a blocking select should follow. 阻塞选择操作 */ int SELECT = -1; /** * Indicates the IO loop should be retried, no blocking select to follow directly. 如果没有选择操作阻塞,预示着应该重试IO事件循环,处理IO事件 */ int CONTINUE = -2; /** * The {@link SelectStrategy} can be used to steer the outcome of a potential select * call. *选择策略可以用于控制潜在的选择操作结果 * @param selectSupplier The supplier with the result of a select result. 选择结果提供者 * @param hasTasks true if tasks are waiting to be processed. 是否有任务待处理 * @return {@link #SELECT} if the next step should be blocking select {@link #CONTINUE} if * the next step should be to not select but rather jump back to the IO loop and try * again. Any value >= 0 is treated as an indicator that work needs to be done. 如果返回结果为-1,则下一步应该阻塞选择操作,如果返回结果为-2,则下一步应该调回IO事件循环,处理 IO事件,而不是继续执行选择操作,返回值大于0,表示需要有工作要做,即注册到选择器的选择通道有IO事件 就绪。 */ int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception; }
从上面可以看出,Nio事件循环内部有一个取消选择key计数器清理间隔CLEANUP_INTERVAL,用于当取消的选择key达到256个时,重置取消选择key计数器cancelledKeys(int),并重新进行选择操作;选择器自动重构阈值SELECTOR_AUTO_REBUILD_THRESHOLD,默认选择操作发生512次,用于控制当选择器发生多少次选择操作时,重构选择器;选择器状态判断器selectNowSupplier,用于获取Nio事件循环内部选择器的选择操作结果;同时有一个选择器selector,未包装过的选择器unwrappedSelector和一个选择器提供者provider,一个选择key就绪集合selectedKeys(SelectedSelectionKeySet);当选择器的选择操作阻塞时,wakenUp(AtomicBoolean)属性决定是否应该break选择操作过程;一个Nio处理Io事件的时间占比ioRatio(int),默认为50,即IO事件处理时间和其他事件处理时间各占Nio事件循环一半;一个选择策略selectStrategy用于控制选择循环,如果返回结果为-1,则下一步应该阻塞选择操作,如果返回结果为-2,则下一步应该调回IO事件循环,处理IO事件,而不是继续执行选择操作,返回值大于0,表示需要有工作要做,即注册到选择器的选择通道有IO事件就绪。
回到Nio事件循环构造:
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"); } provider = selectorProvider; //打开选择器 final SelectorTuple selectorTuple = openSelector(); selector = selectorTuple.selector; unwrappedSelector = selectorTuple.unwrappedSelector; selectStrategy = strategy; }
先看一下选择器元组SelectorTuple的定义:
private static final class SelectorTuple { final Selector unwrappedSelector; final Selector selector; SelectorTuple(Selector unwrappedSelector) { this.unwrappedSelector = unwrappedSelector; this.selector = unwrappedSelector; } SelectorTuple(Selector unwrappedSelector, Selector selector) { this.unwrappedSelector = unwrappedSelector; this.selector = selector; } }
选择器元组SelectorTuple实际为选择器和未包装选择器的包装类
再来看打开选择器:
//打开选择器 final SelectorTuple selectorTuple = openSelector();
private SelectorTuple openSelector() { final Selector unwrappedSelector; try { //从选择器提供者打开一个选择器,刚打开的选择器是未包装的选择器,裸选择器 unwrappedSelector = provider.openSelector(); } catch (IOException e) { throw new ChannelException("failed to open a new selector", e); } //如果key集合不优化,则选择器默认为选择器提供者打开的选择器 if (DISABLE_KEYSET_OPTIMIZATION) { return new SelectorTuple(unwrappedSelector); } //下面是优化选择器集合 final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet(); //在当前线程访问控制选择下,加载选择器实现类,不初始化 Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { try { return Class.forName( "sun.nio.ch.SelectorImpl", false, PlatformDependent.getSystemClassLoader()); } catch (Throwable cause) { return cause; } } }); //如果从系统类加载器加载的选择key实现类不是Class实例,或不是裸选择器类型,不进行选择器key集合优化 if (!(maybeSelectorImplClass instanceof Class) || // ensure the current selector implementation is what we can instrument. !((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); } final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass; Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { try { //在当前线程相同访问控制权限下,获取系统选择器实现类的 //选择器就绪key集合selectedKeysField及其代理publicSelectedKeysField Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys"); Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys"); //设置选择器就绪key集合selectedKeysField及其代理publicSelectedKeysField访问控制权限 Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField); if (cause != null) { return cause; } cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField); if (cause != null) { return cause; } //将系统选择器的就绪key集合selectedKeysField及其代理publicSelectedKeysField //设置为selectedKeySet selectedKeysField.set(unwrappedSelector, selectedKeySet); publicSelectedKeysField.set(unwrappedSelector, selectedKeySet); return null; } catch (NoSuchFieldException e) { return e; } catch (IllegalAccessException e) { return e; } } }); if (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); } //初始化选择key集合 selectedKeys = selectedKeySet; logger.trace("instrumented a special java.util.Set into: {}", unwrappedSelector); return new SelectorTuple(unwrappedSelector, new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet)); }
再来看选择器包装类
//SelectedSelectionKeySetSelector
package io.netty.channel.nio; import java.io.IOException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.spi.SelectorProvider; import java.util.Set; final class SelectedSelectionKeySetSelector extends Selector { private final SelectedSelectionKeySet selectionKeys;//就绪的选择key集合 private final Selector delegate;//选择器代理 SelectedSelectionKeySetSelector(Selector delegate, SelectedSelectionKeySet selectionKeys) { this.delegate = delegate; this.selectionKeys = selectionKeys; } @Override public boolean isOpen() { return delegate.isOpen(); } @Override public SelectorProvider provider() { return delegate.provider(); } @Override public Set<SelectionKey> keys() { return delegate.keys(); } @Override public Set<SelectionKey> selectedKeys() { return delegate.selectedKeys(); } //每次选择操作,重置就绪选择key集合 @Override public int selectNow() throws IOException { selectionKeys.reset(); return delegate.selectNow(); } @Override public int select(long timeout) throws IOException { selectionKeys.reset(); return delegate.select(timeout); } @Override public int select() throws IOException { selectionKeys.reset(); return delegate.select(); } @Override public Selector wakeup() { return delegate.wakeup(); } @Override public void close() throws IOException { delegate.close(); } }
选择器包装类的每次选择操作,首先重置就绪选择key集合,再讲相应的操作委托给内部选择器代理,其他打开唤醒等方法直接委托给内部选择器代理。
从上面可以看出,打开选择器,主要是委托给选择器提供者,如果需要优化选择器的,
在当前线程访问控制选择下,加载选择器实现类,不初始化,如果从系统类加载器加载的选择key实现类不是Class实例,或不是裸选择器类型,不进行选择器key集合优化,及选择器为选择器提供者打开的裸选择器;否则在当前线程相同访问控制权限下,获取系统选择器实现类的,选择器就绪key集合selectedKeysField及其代理publicSelectedKeysField,设置选择器就绪key集合selectedKeysField及其代理publicSelectedKeysField访问控制权限,将系统选择器的就绪key集合selectedKeysField及其代理publicSelectedKeysField设值为
selectedKeySet(SelectedSelectionKeySet),并将选择器selector包装为SelectedSelectionKeySetSelector。
Nio事件循环初始化,主要是将Nio事件循环组和事件执行器及任务拒绝策略传给父类,同时打开一个选择器。
总结:
Nio事件循环内部有一个取消选择key计数器清理间隔CLEANUP_INTERVAL,用于当取消的选择key达到256个时,重置取消选择key计数器cancelledKeys(int),并重新进行选择操作;选择器自动重构阈值SELECTOR_AUTO_REBUILD_THRESHOLD,默认选择操作发生512次,用于控制当选择器发生多少次选择操作时,重构选择器;选择器状态判断器selectNowSupplier,用于获取Nio事件循环内部选择器的选择操作结果;同时有一个选择器selector,未包装过的选择器unwrappedSelector和一个选择器提供者provider,一个选择key就绪集合selectedKeys(SelectedSelectionKeySet);当选择器的选择操作阻塞时,wakenUp(AtomicBoolean)属性决定是否应该break选择操作过程;一个Nio处理Io事件的时间占比ioRatio(int),默认为50,即IO事件处理时间和其他事件处理时间各占Nio事件循环一半;一个选择策略selectStrategy用于控制选择循环,如果返回结果为-1,则下一步应该阻塞选择操作,如果返回结果为-2,则下一步应该调回IO事件循环,处理IO事件,而不是继续执行选择操作,返回值大于0,表示需要有工作要做,即注册到选择器的选择通道有IO事件就绪。
Nio事件循环初始化,主要是将Nio事件循环组和事件执行器及任务拒绝策略传给父类单线程事件循环(单线程事件执行器),同时打开一个选择器。
打开选择器过程,委托给选择器提供者打开一个选择器,如果需要优化选择器的,在当前线程访问控制选择下,加载选择器实现类,不初始化,如果从系统类加载器加载的选择key实现类不是Class实例,或不是裸选择器类型,不进行选择器key集合优化,及选择器为选择器提供者打开的裸选择器;否则在当前线程相同访问控制权限下,获取系统选择器实现类的,选择器就绪key集合selectedKeysField及其代理publicSelectedKeysField,设置选择器就绪key集合selectedKeysField及其代理publicSelectedKeysField访问控制权限,将系统选择器的就绪key集合selectedKeysField及其代理publicSelectedKeysField设值为
selectedKeySet(SelectedSelectionKeySet),并将选择器selector包装为SelectedSelectionKeySetSelector。
附:
下面的选择key集合和反射工具,简单看看就行。
//SelectedSelectionKeySet
package io.netty.channel.nio; import java.nio.channels.SelectionKey; import java.util.AbstractSet; import java.util.Arrays; import java.util.Iterator; final class SelectedSelectionKeySet extends AbstractSet<SelectionKey> { SelectionKey[] keys; int size; SelectedSelectionKeySet() { keys = new SelectionKey[1024]; } @Override public boolean add(SelectionKey o) { if (o == null) { return false; } keys[size++] = o; if (size == keys.length) { increaseCapacity(); } return true; } @Override public int size() { return size; } @Override public boolean remove(Object o) { return false; } @Override public boolean contains(Object o) { return false; } @Override public Iterator<SelectionKey> iterator() { throw new UnsupportedOperationException(); } void reset() { reset(0); } void reset(int start) { Arrays.fill(keys, start, size, null); size = 0; } private void increaseCapacity() { SelectionKey[] newKeys = new SelectionKey[keys.length << 1]; System.arraycopy(keys, 0, newKeys, 0, size); keys = newKeys; } }
//ReflectionUtil
package io.netty.util.internal; import java.lang.reflect.AccessibleObject; public final class ReflectionUtil { private ReflectionUtil() { } /** * Try to call {@link AccessibleObject#setAccessible(boolean)} but will catch any {@link SecurityException} and * {@link java.lang.reflect.InaccessibleObjectException} and return it. * The caller must check if it returns {@code null} and if not handle the returned exception. */ public static Throwable trySetAccessible(AccessibleObject object) { try { object.setAccessible(true); return null; } catch (SecurityException e) { return e; } catch (RuntimeException e) { return handleInaccessibleObjectException(e); } } private static RuntimeException handleInaccessibleObjectException(RuntimeException e) { // JDK 9 can throw an inaccessible object exception here; since Netty compiles // against JDK 7 and this exception was only added in JDK 9, we have to weakly // check the type if ("java.lang.reflect.InaccessibleObjectException".equals(e.getClass().getName())) { return e; } throw e; } }
发表评论
-
netty NioSocketChannel解析
2017-09-29 12:50 1321netty 抽象BootStrap定义:http://dona ... -
netty Pooled字节buf分配器
2017-09-28 13:00 2057netty 字节buf定义:http://donald-dra ... -
netty Unpooled字节buf分配器
2017-09-26 22:01 2443netty 字节buf定义:http://donald-dra ... -
netty 抽象字节buf分配器
2017-09-26 08:43 1316netty 字节buf定义:http:// ... -
netty 复合buf概念
2017-09-25 22:31 1310netty 字节buf定义:http://donald-dra ... -
netty 抽象字节buf引用计数器
2017-09-22 12:48 1593netty 字节buf定义:http://donald-dra ... -
netty 抽象字节buf解析
2017-09-22 09:00 1843netty 通道接口定义:http://donald-drap ... -
netty 资源泄漏探测器
2017-09-21 09:37 1397netty 通道接口定义:http://donald-drap ... -
netty 字节buf定义
2017-09-20 08:31 2833netty 通道接口定义:http://donald-drap ... -
netty 默认通道配置后续
2017-09-18 08:36 2177netty 通道接口定义:http://donald-drap ... -
netty 默认通道配置初始化
2017-09-17 22:51 2036netty 通道接口定义:http://donald-drap ... -
netty 通道配置接口定义
2017-09-17 14:51 1078netty 通道接口定义:http://donald-drap ... -
netty NioServerSocketChannel解析
2017-09-16 13:01 1876netty ServerBootStrap解析:http:// ... -
netty 抽象nio消息通道
2017-09-15 15:30 1217netty 通道接口定义:http:/ ... -
netty 抽象nio字节通道
2017-09-14 22:39 1201netty 通道接口定义:http:/ ... -
netty 抽象nio通道解析
2017-09-14 17:23 957netty 通道接口定义:http://donald-drap ... -
netty 抽象通道后续
2017-09-13 22:40 1309netty Inboudn/Outbound通道Inv ... -
netty 通道Outbound缓冲区
2017-09-13 14:31 2189netty 通道接口定义:http:/ ... -
netty 抽象Unsafe定义
2017-09-12 21:24 1076netty 通道接口定义:http:/ ... -
netty 抽象通道初始化
2017-09-11 12:56 1855netty 管道线定义-ChannelPipeline:htt ...
相关推荐
3. **Bootstrap**: 用于初始化服务器或客户端配置的启动类,可以设置处理器链、绑定地址等。 4. **ChannelHandler**: 处理I/O事件或拦截I/O操作的接口,可以自定义实现业务逻辑。常见的有`...
从中你可以了解到如何配置ChannelHandler(处理I/O事件)、定义ByteToMessageDecoder和MessageToByteEncoder(进行数据编解码)以及设置ServerBootstrap和Bootstrap(分别用于服务器和客户端的初始化)。 总的来说...
Netty的`Bootstrap`类是用来初始化和配置服务器的启动参数,如绑定的IP地址和端口号、事件循环组、处理器链等。例如,我们可以通过以下代码创建一个简单的Netty服务器: ```java EventLoopGroup bossGroup = new ...
7. **ChannelInitializer**:用于初始化新创建的Channel,设置其Pipeline中的处理器。 Netty的事件驱动模型是它高效性能的关键。当接收到网络事件时,如连接建立、数据到达、连接关闭等,Netty会将这些事件封装成...
Bootstrap则是用来创建和初始化服务器或客户端连接的工具类。 总的来说,这份《Netty权威指南第二版》的源代码是一个深入理解Netty内部工作原理、学习如何构建高效网络应用的宝贵资源。通过实际操作和学习这些代码...
这些文件通常包含Java类,展示了如何在Netty的事件循环中处理I/O操作。 总之,Spring Boot集成原生Netty提供了构建高性能网络服务的可能性,使得开发者可以充分利用Netty的灵活性和性能优势,同时保留Spring Boot的...
- **初始化阶段**:创建 Bootstrap(启动器),配置 ServerBootstrap(服务器启动器)或 Bootstrap(客户端启动器),设置 NIO 事件循环组、ServerSocketChannel 或 SocketChannel、编解码器等。 - **绑定与连接**...
- `NioEventLoopGroup`:针对NIO的事件循环组实现。 - `EpollEventLoopGroup`:专门针对Linux系统的EPOLL机制的事件循环组实现。 - `ServerBootstrap` 和 `Bootstrap`:分别用于创建服务端和客户端的引导类。 ##...
1. **NioSocketChannel初始化**: 这个过程涉及到Netty对Socket连接的抽象,包括连接状态的管理以及读写操作的处理。初始化时,Netty会为每个新连接创建一个Channel实例,这个实例与实际的Socket连接关联。 2. **...
7. **Handler的生命周期**:Netty的Handler有添加、激活、销毁等生命周期方法,可以用来初始化、清理资源或者进行状态变更的处理。 8. **多协议支持**:Netty通过协议编解码器支持多种网络协议,如TCP、UDP、HTTP、...
Bootstrap负责初始化和配置网络连接,Channel是网络I/O操作的抽象,EventLoop负责监听和处理事件,而Pipeline则是一系列处理器的链,每个处理器处理特定类型的事件或数据。 Netty的非阻塞I/O模型允许它在高并发环境...
- `channelActive`: 当客户端连接成功时调用,可以在这里发送欢迎信息或进行初始化操作。 - `channelRead0/channelRead`: 处理接收到的数据,这是读取并处理客户端发送消息的主要方法。 - `exceptionCaught`: ...
通过内嵌的Tomcat或Jetty服务器,自动配置特性以及“约定优于配置”的原则,SpringBoot极大地简化了项目的初始化和配置过程。 在本项目中,Netty被用作通信层,处理客户端的连接请求,接收和发送数据。Netty提供了...
- 配置与初始化:通过Bootstrap和ServerBootstrap配置网络连接参数,构建ChannelPipeline。 4. **Netty的异步I/O** - NIO基础:Netty基于Java NIO API,提供了更高级别的抽象。 - Selectors与多路复用:Netty...
6. **Bootstrap(引导类)**:用于初始化和配置服务器或客户端。通过设置ChannelFactory、Group、Pipeline等,然后调用bind或connect方法启动服务。 7. **EventLoopGroup(事件循环组)**:一组EventLoop,每个...
6. **Netty源码剖析**:笔记-12探讨了Netty的启动过程,这对于理解Netty如何初始化和运行至关重要。此外,这也有助于开发者在遇到问题时能更深入地排查和解决问题。 7. **心跳检测和空闲连接处理**:笔记-7讲述了...
- Channel初始化和绑定端口 - 编写自定义Handler以处理数据 - 使用ByteBuf读写数据 - 异步通信和回调机制的实现 - 可能还有WebSocket、HTTP服务器等高级示例 6. **学习和使用Netty的益处** - 提升网络应用的...
.childHandler(new ChannelInitializer() { // 初始化Channel @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new MyBusinessHandler()); // 添加自定义的...