nio的源码都是和具体的操作系统底层的io模型有关,都是底层的东西,分析意义不大。
linux的底层支持以及几种io对比
比如nio就是linux的多路复用io模型,aio是信号驱动io模型。
先说结论:
一个EventLoopGroup,可以看作一个线程池,里面维护了一个EventLoop数组,一个EventLoop其实也是一个线程池,只不过EventLoop是一个单线程池而已,所以可以把EventLoop看做一个线程。
Server端,主线程会使用一个EventLoop去启动一个线程去循环select,然后主线程注册
服务端:
public static void main(String[] args) {
EventLoopGroup bossstrap = new NioEventLoopGroup();
EventLoopGroup workerstrap = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossstrap, workerstrap)
.channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new MyServerInitializer());
try {
ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossstrap.shutdownGracefully();
workerstrap.shutdownGracefully();
}
}
从上往下分析:EventLoopGroup继承于MultithreadEventLoopGroup
EventLoopGroup bossstrap = new NioEventLoopGroup();
public NioEventLoopGroup() {
this(0);
}
public NioEventLoopGroup(int nThreads) {
this(nThreads, (Executor) null);
}
public NioEventLoopGroup(int nThreads, Executor executor) {
this(nThreads, executor, SelectorProvider.provider());
}
public NioEventLoopGroup(
int nThreads, Executor executor, final SelectorProvider selectorProvider) {
this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}
public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory) {
super(nThreads, executor, selectorProvider, selectStrategyFactory);
}
// 注意,这里,如果不传参,则默认的线程池大小为cpu线程数*2。
private static final int DEFAULT_EVENT_LOOP_THREADS;
static {
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
}
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
}
// 不传入executor,则executor为ThreadPerTaskExecutor,这个线程池其实
//是给单个EventLoop用的,ThreadPerTaskExecutor线程池execute一个任务,
//启动一个线程池,但是其实Eventloop只会运行一次ThreadPerTaskExecutor的execute方法,也就是单线程运行。
// 这个executor是后面创建EventLoop的传参,也就是EventLoop里的线程池是这个线程池
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
// 维护了一个EventExecutor数组,EventLoop是EventExecutor的子接口,
// 所以其实就是维护了一个EventLoop数组
children = new EventExecutor[nThreads];
// 根据数组长度是否是2次方,创建线程池选择线程的选择器,
// 了解就好
if (isPowerOfTwo(children.length)) {
chooser = new PowerOfTwoEventExecutorChooser();
} else {
chooser = new GenericEventExecutorChooser();
}
// 循环创建EventLoop
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
/**
newChild创建EventLoop,调用的是NioEventLoopGroup的方法
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy());
}
*/
// 把前面提到的ThreadPerTaskExecutor线程池传过去了,
//ThreadPerTaskExecutor其实是EventLoop维护的,用来真正启动线程的
// 这里很重要,这里生成eventLoop,EventLoop里面维护了select,select不是淡
// 出的nio的select,而是反射修改了nio select的成员变量selectkey,使得后面,
// 直接select()方法,netty能够直接获取到selectKey
// 看下文
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
// TODO: Think about if this is a good exception type
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
// 不成功,则关掉资源,不看
if (!success) {
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
}
for (int j = 0; j < i; j ++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
// Let the caller handle the interruption.
Thread.currentThread().interrupt();
break;
}
}
}
}
}
// 下面添加结束监听器,暂时忽略
final FutureListener