前言
这篇帖子我估计要反复修改,我不确定面试官是不是随口问的(就是可能他自己也没仔细想过这个问题。。。),我当时回答的是不能,我确实不大明白为啥要合在一起,合在一起你也是要有线程去处理连接,一部分线程去处理请求。而且放在一起不是增加复杂度(耦合)了吗?面试的时候思路容易不清晰,其实这段还是看过的,而且之前的帖子里还写过,netty源码默认就是支持的,只不过平时使用的都是主从多线程reactor。
相关知识点
Netty中的三种线程模型?
单线程Reactor、多线程Reactor、主从多线程Reactor(前面已经介绍过了)。
boss线程和worker线程 ?
Boss线程:每个server服务器都会有一个boss线程,每绑定一个InetSocketAddress都会产生一个boss线程,比如:我们开启了两个服务器端口80和443,则我们会有两个boss线程。一个boss线程在端口绑定后,会接收传进来的连接,一旦连接接收成功,boss线程会指派一个worker线程处理连接。
Worker线程:一个NioServerSocketChannelFactory会有一个或者多个worker线程。一个worker线程在非阻塞模式下为一个或多个Channels提供非阻塞读或写。
偷张图:
Group构造器
平时都是这么用的(主从多线程):
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap sb = new ServerBootstrap();
sb.option(ChannelOption.SO_BACKLOG, 1024);
sb.group(group, bossGroup) // 绑定线程池
.channel(NioServerSocketChannel.class) // 指定使用的channel
.localAddress(this.port)// 绑定监听端口
...略
跟一下源码:
/**
* Specify the {@link EventLoopGroup} which is used for the parent (acceptor) and the child (client).
*/
@Override
public ServerBootstrap group(EventLoopGroup group) {
return group(group, group);
}
/**
* Set the {@link EventLoopGroup} for the parent (acceptor) and the child (client). These
* {@link EventLoopGroup}'s are used to handle all the events and IO for {@link ServerChannel} and
* {@link Channel}'s.
*/
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
super.group(parentGroup);
if (childGroup == null) {
throw new NullPointerException("childGroup");
}
if (this.childGroup != null) {
throw new IllegalStateException("childGroup set already");
}
this.childGroup = childGroup;
return this;
}
这里提供了两个构造器,单参数即为连接与请求处理线程公用的线程池( which is used for the parent (acceptor) and the child (client).),当 EventLoopGroup bossGroup = new NioEventLoopGroup()不填值时,默认为cpu核数*2,EventLoopGroup bossGroup = new NioEventLoopGroup(1)则为单线程reactor模型;当调用的构造器为两个参数时,则是常用的多线程模型,通常也有这种写法:
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
这里就是boss线程池大小为1,worker线程池大小为cpu核数*2,这里就有一个问题,boss thread只有一个, 但是为什么要用thread pool? 原因如下:
1.可能有多个channel factory, 这些factory可以共用一个boss thread pool来创建boss thread.。
2.boss thread可以中途进行释放, 为了避免重复create的开销, 可以用一个小型的thread pool来管理 。
总结
多看源码,温故知新!