netty源码分析(十七)Netty线程模型深度解读与架构设计原则
来源:互联网 发布:linux两个mysql 编辑:程序博客网 时间:2024/06/04 23:25
上次分析到:
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop public ChannelFuture register(final ChannelPromise promise) { ObjectUtil.checkNotNull(promise, "promise"); promise.channel().unsafe().register(this, promise); return promise; }}
之前提到的ChannelPromise 结构,其实是一个异步返回结果的封装,它持有channel和当前的SingleThreadEventLoop :
进入unsafe实现类AbstractUnsafe的register方法:
protected abstract class AbstractUnsafe implements Unsafe { private volatile ChannelOutboundBuffer outboundBuffer = new ChannelOutboundBuffer(AbstractChannel.this); private RecvByteBufAllocator.Handle recvHandle; private boolean inFlush0; /** true if the channel has never been registered, false otherwise */ private boolean neverRegistered = true; public final void register(EventLoop eventLoop, final ChannelPromise promise) { if (eventLoop == null) { throw new NullPointerException("eventLoop"); } if (isRegistered()) { promise.setFailure(new IllegalStateException("registered to an event loop already")); return; } if (!isCompatible(eventLoop)) { promise.setFailure( new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName())); return; } //上边的逻辑主要是一些非空判断之类的东西 AbstractChannel.this.eventLoop = eventLoop; //主要的注册逻辑分支,if和else分支可以看到最后调用的都是register0,但是else里边加了一个外壳---线程 if (eventLoop.inEventLoop()) { register0(promise); } else { try { eventLoop.execute(new Runnable() { @Override public void run() { register0(promise); } }); } catch (Throwable t) { logger.warn( "Force-closing a channel whose registration task was not accepted by an event loop: {}", AbstractChannel.this, t); closeForcibly(); closeFuture.setClosed(); safeSetFailure(promise, t); } } }}
eventLoop.inEventLoop()是分支逻辑的主要判断依据(eventLoop实体是SingleThreadEventExecutor):
public interface EventExecutor extends EventExecutorGroup {...略 /** * Calls {@link #inEventLoop(Thread)} with {@link Thread#currentThread()} as argument * 将当前线程作为参数。 */ boolean inEventLoop(); ...略 }
找到他的实现类:
public abstract class AbstractEventExecutor extends AbstractExecutorService implements EventExecutor { ...略 public boolean inEventLoop() { return inEventLoop(Thread.currentThread());//参数为当前线程。 } ...略}
在SingleThreadEventExecutor:
public boolean inEventLoop(Thread thread) { return thread == this.thread; }
很简单,即,判断当前线程是不是SingleThreadEventExecutor里边维护的线程。所以else里边的逻辑是SingleThreadEventExecutor里边的线程不是当前线程的时候,新建一个Thread去执行register0,下边看一下register0的逻辑:
private void register0(ChannelPromise promise) { try { // check if the channel is still open as it could be closed in the mean time when the register // call was outside of the eventLoop if (!promise.setUncancellable() || !ensureOpen(promise)) { return; } boolean firstRegistration = neverRegistered; doRegister();//核心注册方法 neverRegistered = false; registered = true; // Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the // user may already fire events through the pipeline in the ChannelFutureListener. pipeline.invokeHandlerAddedIfNeeded(); safeSetSuccess(promise); pipeline.fireChannelRegistered(); // Only fire a channelActive if the channel has never been registered. This prevents firing // multiple channel actives if the channel is deregistered and re-registered. if (isActive()) { if (firstRegistration) { pipeline.fireChannelActive(); } else if (config().isAutoRead()) { // This channel was registered before and autoRead() is set. This means we need to begin read // again so that we process inbound data. // // See https://github.com/netty/netty/issues/4805 beginRead(); } } } catch (Throwable t) { // Close the channel directly to avoid FD leak. closeForcibly(); closeFuture.setClosed(); safeSetFailure(promise, t); } }
看一下doRegister():
看一下AbstractNioChannel 实现类的doRegister逻辑:
public abstract class AbstractNioChannel extends AbstractChannel {...略 protected void doRegister() throws Exception { boolean selected = false; for (;;) { try { selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this); //javaChannel()返回的是SelectableChannel(jdk的java.nio.channels.SelectableChannel) //javaChannel().register是将channel注册到Selector上去,所以eventLoop().unwrappedSelector()返回的是Selector //(jdk的java.nio.channels.Selector) return; } catch (CancelledKeyException e) { if (!selected) { // Force the Selector to select now as the "canceled" SelectionKey may still be // cached and not removed because no Select.select(..) operation was called yet. eventLoop().selectNow(); selected = true; } else { // We forced a select operation on the selector before but the SelectionKey is still cached // for whatever reason. JDK bug ? throw e; } } } } ...略}
到这里我们看到了最终netty的JavaNio的注册实现。最后说一下比较重要的一点,上边提到的主要的注册逻辑分支,if和else分支可以看到最后调用的都是register0,但是else里边加了一个外壳—线程,这个地方有这么五点需要注意:
- 一个EventLoopGroup当中会包含一个或多个EventLoop。
- 一个EventLoop在它的整个生命周期当中都只会与唯一一个Thread进行绑定。
- 所有由EventLoop所处理的各种I/O事件都将在它所关联的那个Thread上进行处理。
- 一个Channel在它的整个生命周期中只会注册在一个EventLoop上。
- 一个EventLoop在运行过程中,会被分配给一个或多个Channel。
这是netty的核心的架构理念,非常重要!!!
阅读全文
0 0
- netty源码分析(十七)Netty线程模型深度解读与架构设计原则
- netty源码分析(十三)Netty核心四大组件关系与构建方式深度解读
- [netty源码分析]--EventLoopGroup与EventLoop 分析netty的线程模型
- 【Netty源码分析】Reactor线程模型
- netty源码分析 之十三 线程模型
- Netty源码分析之Reactor线程模型
- Netty源码解读之线程
- Netty源码解读之线程
- netty源码分析(十五)Channel注册流程深度解读
- 【Netty】Netty系列之Netty线程模型
- netty源码分析(二十一)Netty数据容器ByteBuf底层数据结构深度剖析与ReferenceCounted初探
- Netty源码解读(四)Netty与Reactor模式
- Netty源码解读(四)Netty与Reactor模式
- Netty源码解读(四)Netty与Reactor模式
- Netty源码解读(四)Netty与Reactor模式
- Netty源码解读(四)Netty与Reactor模式
- Netty源码解读(四)Netty与Reactor模式
- Netty源码解读——Netty与Reactor模式
- 关于微信支付以及获取签名的正确方法
- 简单的圆形三角形
- 187. Repeated DNA Sequences
- 一位资深程序员大牛给予Java的学习路线建议
- 【论文笔记】视频物体检测(VID)系列 FGFA:Flow-Guided Feature Aggregation for Video Object Detection
- netty源码分析(十七)Netty线程模型深度解读与架构设计原则
- linux poll()系统调用函数介绍
- jpbm数据表结构
- div+css(实体与边框)六边形
- 害死人不偿命的(3n+1)猜想
- 进步中
- PAT乙级系列:第一题
- HDOJ—1798 Tell me the area
- Asteroids