EventLoop系列源码分析
EventLoopGroup 和 EventLoop 代码分析
在刚开始介绍Netty时笔者曾手写过一个Netty的Demo,其实那里面用到了很多常用的组件,并且Netty在使用上代码基本都是那一套,那么这些代码每一行都做了什么事?底层的原理是什么?接下来就一一讲解这段代码的底层运行流程:为了防止大家忘记,这里将代码贴出来
//eventLoop暂时理解为线程组
EventLoopGroup group = new NioEventLoopGroup();
try {
//ServerBootStrap是启动必备的,启动相关的工作基本都是由它完成的
ServerBootstrap sb = new ServerBootstrap();
sb.group(group)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ServerChannelInitializer());
//bind()方法是整个服务启动的一个关键方法,并且同步
ChannelFuture future = sb.bind().sync();
future.channel().closeFuture().sync();
}finally {
group.shutdownGracefully().sync();
}
首先就是EventLoopGroup group = new NioEventLoopGroup(),这里创建的是NioEventLoopGroup,一路查看下来,会执行MultithreadEventLoopGroup的构造函数:
MultithreadEventLoopGroup的构造函数需要关注的是它会判断是否有限制线程数,如果nThreads=0则需要拿到CPU核心数*2来作为线程数,这个构造函数又调用了父类的构造函数super,父类是 MultithreadEventExecutorGroup,所以进入 MultithreadEventExecutorGroup的构造函数看看:
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) {
this.terminatedChildren = new AtomicInteger();
this.terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
} else {
//首先会判断executor是否实例化,如果为null则实例化ThreadPerTaskExecutor
//ThreadPerTaskExecutor这个类有个成员变量TreadFatory,专门new线程的
//当调用executor的execute方法时才真的创建一个线程,此时还未与EventLoop挂钩
//要和NioEventLoop的线程挂钩则在SingleThreadEventExecutor的doStartThread方法里
if (executor == null) {
executor = new ThreadPerTaskExecutor(this.newDefaultThreadFactory());
}
//这个就是存EventExecutor(实际是NioEventLoop)的实例数组,并在循环里new出每个EventLoop实例
this.children = new EventExecutor[nThreads];
int j;
for(int i = 0; i < nThreads; ++i) {
boolean success = false;
boolean var18 = false;
try {
var18 = true;
//这个newChild方法就是调用NioEventLoopGroup的newChild方法来创建NioEventLoop
//接下来看看这个newChild的实现
this.children[i] = this.newChild((Executor)executor, args);
success = true;
var18 = false;
} catch (Exception var19) {
throw new IllegalStateException("failed to create a child event loop", var19);
} finally {
if (var18) {
if (!success) {
int j;
for(j = 0; j < i; ++j) {
this.children[j].shutdownGracefully();
}
for(j = 0; j < i; ++j) {
EventExecutor e = this.children[j];
try {
while(!e.isTerminated()) {
e.awaitTermination(2147483647L, TimeUnit.SECONDS);
}
} catch (InterruptedException var20) {
Thread.currentThread().interrupt();
break;
}
}
}
}
}
if (!success) {
for(j = 0; j < i; ++j) {
this.children[j].shutdownGracefully();
}
for(j = 0; j < i; ++j) {
EventExecutor e = this.children[j];
try {
while(!e.isTerminated()) {
e.awaitTermination(2147483647L, TimeUnit.SECONDS);
}
} catch (InterruptedException var22) {
Thread.currentThread().interrupt();
break;
}
}
}
}
this.chooser = chooserFactory.newChooser(this.children);
FutureListener<Object> terminationListener = new FutureListener<Object>() {
public void operationComplete(Future<Object> future) throws Exception {
if (MultithreadEventExecutorGroup.this.terminatedChildren.incrementAndGet() == MultithreadEventExecutorGroup.this.children.length) {
MultithreadEventExecutorGroup.this.terminationFuture.setSuccess((Object)null);
}
}
};
EventExecutor[] var24 = this.children;
j = var24.length;
for(int var26 = 0; var26 < j; ++var26) {
EventExecutor e = var24[var26];
e.terminationFuture().addListener(terminationListener);
}
Set<EventExecutor> childrenSet = new LinkedHashSet(this.children.length);
Collections.addAll(childrenSet, this.children);
this.readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
}
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
//直接调用了NioEventLoop的构造函数
return new NioEventLoop(this, executor, (SelectorProvider)args[0], ((SelectStrategyFactory)args[1]).newSelectStrategy(), (RejectedExecutionHandler)args[2]);
}
public final class NioEventLoop extends SingleThreadEventLoop {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioEventLoop.class);
private static final int CLEANUP_INTERVAL = 256;
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;
private final IntSupplier selectNowSupplier = new IntSupplier() {
public int get() throws Exception {
return NioEventLoop.this.selectNow();
}
};
private final Callable<Integer> pendingTasksCallable = new Callable<Integer>() {
public Integer call() throws Exception {
return NioEventLoop.super.pendingTasks();
}
};
//事件选择器
private Selector selector;
private Selector unwrappedSelector;
private SelectedSelectionKeySet selectedKeys;
private final SelectorProvider provider;
private final AtomicBoolean wakenUp = new AtomicBoolean();
private final SelectStrategy selectStrategy;
private volatile int ioRatio = 50;
private int cancelledKeys;
private boolean needsToSelectAgain;
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");
} else if (strategy == null) {
throw new NullPointerException("selectStrategy");
} else {
this.provider = selectorProvider;
//这里调用了openSelector()方法生成SelectorTuple,而在openSelector()里面实际上是
//调用了provider.openSelector()生成了selector赋值给了SelectorTuple
//所以下面可以拿到selector,这个过程和原生的NIO编程是一样的过程
NioEventLoop.SelectorTuple selectorTuple = this.openSelector();
this.selector = selectorTuple.selector;
this.unwrappedSelector = selectorTuple.unwrappedSelector;
this.selectStrategy = strategy;
}
}
我们之前有说过,每个EventLoop其实是一个只有一个线程的线程池(SingleThreadPool),内部维护着一个线程 Thread 和几个阻塞队列,那么是否可以证明呢?
每个EventLoop包含的线程Thread定义在父类SingleThreadEventExecutor中,而每个EventLoop包含有两个队列,一个是SingleThreadEventExecutor中的taskQueue,主要负责保存各种任务,比如处理事件等,另一个是SingleThreadEventLoop中的tailTask,用于每次事件循环后置任务处理。
这也就证明了前面说的结论是正确的。NioEventLoop作为 IO 事件处理的主要组件,必然离不开对事件的处理机制,在 NioEventLoop 的 run 方法,就有 selector 上进行 select 和调用 processSelectedKeys()处理各种事件集。
protected void run() {
while(true) {
while(true) {
try {
switch(this.selectStrategy.calculateStrategy(this.selectNowSupplier, this.hasTasks())) {
//在接口SelectStrategy中,有两个成员变量。SELECT=-1和CONTINUE=-2
case -2:
continue;
case -1:
this.select(this.wakenUp.getAndSet(false));
if (this.wakenUp.get()) {
this.selector.wakeup();
}
default:
this.cancelledKeys = 0;
this.needsToSelectAgain = false;
//ioRatio是一个比例,表示线程处理io事件和处理队列中Task的时间比,缺省值1:1
int ioRatio = this.ioRatio;
if (ioRatio == 100) {
try {
//真正的循环选择器处理事件是在这个processSelectedKeys方法里
this.processSelectedKeys();
} finally {
this.runAllTasks();
}
} else {
long ioStartTime = System.nanoTime();
boolean var13 = false;
try {
var13 = true;
this.processSelectedKeys();
var13 = false;
} finally {
if (var13) {
long ioTime = System.nanoTime() - ioStartTime;
this.runAllTasks(ioTime * (long)(100 - ioRatio) / (long)ioRatio);
}
}
long ioTime = System.nanoTime() - ioStartTime;
this.runAllTasks(ioTime * (long)(100 - ioRatio) / (long)ioRatio);
}
}
} catch (Throwable var21) {
handleLoopException(var21);
}
try {
if (this.isShuttingDown()) {
this.closeAll();
if (this.confirmShutdown()) {
return;
}
}
} catch (Throwable var18) {
handleLoopException(var18);
}
}
}
}
接下来看看processSelectedKeys这个方法:
private void processSelectedKeys() {
if (this.selectedKeys != null) {
this.processSelectedKeysOptimized();
} else {
//processSelectedKeysPlain参数是拿到所有事件的key集合,然后进入这个方法看看
this.processSelectedKeysPlain(this.selector.selectedKeys());
}
}
private void processSelectedKeysPlain(Set<SelectionKey> selectedKeys) {
//接下来的步骤其实跟我们原生的NIO编程步骤大致相似的
if (!selectedKeys.isEmpty()) {
//如果事件集合不为空,就遍历处理事件
Iterator i = selectedKeys.iterator();
while(true) {
SelectionKey k = (SelectionKey)i.next();
//拿到附着的Channel,在AbstractNioChannel中的doRegister方法讲解时,就有说过会把channel附着
//下面会贴出附着的源码图
Object a = k.attachment();
i.remove();
if (a instanceof AbstractNioChannel) {
//处理事件,进这个方法看看
this.processSelectedKey(k, (AbstractNioChannel)a);
} else {
NioTask<SelectableChannel> task = (NioTask)a;
processSelectedKey(k, task);
}
if (!i.hasNext()) {
break;
}
if (this.needsToSelectAgain) {
this.selectAgain();
selectedKeys = this.selector.selectedKeys();
if (selectedKeys.isEmpty()) {
break;
}
i = selectedKeys.iterator();
}
}
}
}
private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
//校验key的可用性
if (!k.isValid()) {
final EventLoop eventLoop;
try {
eventLoop = ch.eventLoop();
} catch (Throwable ignored) {
return;
}
if (eventLoop != this || eventLoop == null) {
return;
}
unsafe.close(unsafe.voidPromise());
return;
}
try {
int readyOps = k.readyOps();
// 连接connect事件
if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
int ops = k.interestOps();
ops &= ~SelectionKey.OP_CONNECT;
k.interestOps(ops);
unsafe.finishConnect();
}
//写write事件
if ((readyOps & SelectionKey.OP_WRITE) != 0) {
ch.unsafe().forceFlush();
}
// 接受连接accept事件 或者 读read事件
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
unsafe.read();
}
} catch (CancelledKeyException ignored) {
unsafe.close(unsafe.voidPromise());
}
}
至此,Netty基本的组件都讲完了,接下来将会从整个Netty的流程来讲前面所讲的组件串起来讲一遍,相信大家听完以后就不会想现在一样感觉学会了又感觉没学会。