20220531_netty服务端ServerBootstrap业务handler绑定对应的线程学习笔记
1概述
我们知道netty服务端端口绑定监听的时候,会创建一个NioServerSocketChannel,同时register选择boss中一个线程进行连接监听处理。
config().group().register(channel)
本节主要分析一下,pipeline().addLast()中增加业务hander时,如何与特定的线程进行绑定的,主要分2中情况:
- 增加到默认的事件循环组中(ch.pipeline().addLast(new TestChannelHandler1())
- 增加到自定义的事件循环组中(ch.pipeline().addLast(eventExecutorGroup3, new TestChannelHandler2()))
.handler(new ChannelInitializer() { // for boss
@Override
public void initChannel(ServerSocketChannel ch) {
// 服务端channel的流水线,增加业务 handler
// 1.默认和 channel 在同一个线程
ch.pipeline().addLast(new TestChannelHandler1());
1.1DefaultChannelHandlerContext类图
DefaultChannelHandlerContext:handler作为通道流水线中每个节点的存储单元。
DefaultChannelHandlerContext:handler 业务处理器
AbstractChannelHandlerContext:name 名称,pipeline 挂载的管道,executor挂载的线程,executionMask(出入栈类型)
1.1.1构建DefaultChannelHandlerContext
private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
// 构建 DefaultChannelHandlerContext
return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
}
1.1.2认线程池(group ==null),设置executor时序
private EventExecutor childExecutor(EventExecutorGroup group) {
if (group == null) { // 直接返回
return null;
}
Boolean pinEventExecutor = channel.config().getOption(ChannelOption.SINGLE_EVENTEXECUTOR_PER_GROUP);
if (pinEventExecutor != null && !pinEventExecutor) {
return group.next();
}
Map childExecutors = this.childExecutors;
if (childExecutors == null) {
// Use size of 4 as most people only use one extra EventExecutor.
childExecutors = this.childExecutors = new IdentityHashMap(4);
}
// Pin one of the child executors once and remember it so that the same child executor
// is used to fire events for the same channel.
EventExecutor childExecutor = childExecutors.get(group);
if (childExecutor == null) {
childExecutor = group.next();
childExecutors.put(group, childExecutor);
}
return childExecutor;
}
// E:\workdirectory\Dev\study\netty-4.1\transport\src\main\java\io\netty\channel\DefaultChannelPipeline.java
@Override
public final ChannelPipeline addLast(ChannelHandler... handlers) {
return addLast(null, handlers);
}
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler);
newCtx = newContext(group, filterName(name, handler), handler); // 此时,executor 仍为null
addLast0(newCtx);
// If the registered is false it means that the channel was not registered on an eventLoop yet.
// In this case we add the context to the pipeline and add a task that will call
// ChannelHandler.handlerAdded(...) once the channel is registered.
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor(); // here,重要的地方来了,核心的判断,得到一个 eventExecutor
if (!executor.inEventLoop()) { // 默认线程组,inEventLoop:true
callHandlerAddedInEventLoop(newCtx, executor);
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
1.1.2.1核心的判断
// 核心的判断
@Override
public EventExecutor executor() {
if (executor == null) { // 如果当前没有挂接线程,则与 channnel共用同一个线程
return channel().eventLoop();
} else {
return executor;
}
}
1.1.3自定义线程池(group != null),设置executor时序
@Override
public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
ObjectUtil.checkNotNull(handlers, "handlers");
for (ChannelHandler h: handlers) {
if (h == null) {
break;
}
addLast(executor, null, h);
}
return this;
}
private EventExecutor childExecutor(EventExecutorGroup group) {
if (group == null) {
return null;
}
// go on,自定义线程组
Boolean pinEventExecutor = channel.config().getOption(ChannelOption.SINGLE_EVENTEXECUTOR_PER_GROUP);
if (pinEventExecutor != null && !pinEventExecutor) {
return group.next();
}
Map childExecutors = this.childExecutors;
if (childExecutors == null) {
// Use size of 4 as most people only use one extra EventExecutor.
childExecutors = this.childExecutors = new IdentityHashMap(4);
}
// Pin one of the child executors once and remember it so that the same child executor
// is used to fire events for the same channel.
EventExecutor childExecutor = childExecutors.get(group);
if (childExecutor == null) {
childExecutor = group.next(); // here,轮询得到一个 eventExecutor
childExecutors.put(group, childExecutor);
}
return childExecutor;
}
1.1.3.1核心的判断
// E:\workdirectory\Dev\study\netty-4.1\common\src\main\java\io\netty\util\concurrent\MultithreadEventExecutorGroup.java
@Override
public EventExecutor next() {
return chooser.next();
}
// E:\workdirectory\Dev\study\netty-4.1\common\src\main\java\io\netty\util\concurrent\DefaultEventExecutorChooserFactory.java
@Override
public EventExecutor next() {
return executors[idx.getAndIncrement() & executors.length - 1];
}
2代码示例
2.1testReregisterByKikop
@Test
public void testReregisterByKikop() throws InterruptedException {
// 线程池1,max:8
// class: NioEventLoop
// 并不是一下子线程全部创建
// poolName:nioEventLoopGroup
// Character.toLowerCase(poolName.charAt(0)) + poolName.substring(1)
// prefix = poolName + '-' + poolId.incrementAndGet() + '-';
// 线程名称定义:nioEventLoopGroup(类驼峰名)-1(工厂标识)-ID(自增)
EventLoopGroup group1 = newEventLoopGroup();
// 线程池3,max:2
// // class: DefaultEventExecutor
final EventExecutorGroup eventExecutorGroup3 = new DefaultEventExecutorGroup(2);
ServerBootstrap bootstrap = new ServerBootstrap();
ChannelFuture future = bootstrap.channel(newChannel()).group(group1)
.childHandler(new ChannelInitializer() { // for work
@Override
public void initChannel(SocketChannel ch) {
}
}).handler(new ChannelInitializer() { // for boss
@Override
public void initChannel(ServerSocketChannel ch) {
// 服务端channel的流水线,增加业务 handler
// 1.默认和 channel 在同一个线程
ch.pipeline().addLast(new TestChannelHandler1());
ch.pipeline().addLast(new TestChannelHandler12());
ch.pipeline().addLast(new TestChannelHandler13());
ch.pipeline().addLast(new TestChannelHandler14());
// eventExecutorGroup 从这里面选一个 defaultEventExecutor,TestChannelHandler2对应线程池3
// ch.pipeline().addLast(eventExecutorGroup3, new TestChannelHandler2());
ch.pipeline().addLast(new TestChannelHandler2());
}
})
.bind(8888).awaitUninterruptibly();
EventLoop eventExecutors = future.channel().eventLoop();
showThreadProperties("eventExecutors", eventExecutors);
// Wait until the connection is closed.
future.channel().closeFuture().sync();
}
2.2TestChannelHandler1
private void showThreadProperties(String executorName, EventExecutor executor) {
if (executor instanceof SingleThreadEventExecutor) {
ThreadProperties threadProperties = ((SingleThreadEventExecutor) executor).threadProperties();
System.out.println(executorName + ":" + threadProperties.name() + ",id" + threadProperties.id());
}
}
private static final class TestChannelHandler1 extends ChannelDuplexHandler {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
System.out.println(this.getClass().toString() + ":" + Thread.currentThread().getName()
+ ",id:" + Thread.currentThread().getId());
}
}
class io.netty.channel.AbstractEventLoopTest$TestChannelHandler2:nioEventLoopGroup-2-1,id:12
class io.netty.channel.AbstractEventLoopTest$TestChannelHandler14:nioEventLoopGroup-2-1,id:12
class io.netty.channel.AbstractEventLoopTest$TestChannelHandler13:nioEventLoopGroup-2-1,id:12
class io.netty.channel.AbstractEventLoopTest$TestChannelHandler12:nioEventLoopGroup-2-1,id:12
class io.netty.channel.AbstractEventLoopTest$TestChannelHandler1:nioEventLoopGroup-2-1,id:12
eventExecutors:nioEventLoopGroup-2-1,id12