1、什么是netty ?
维基百科中的解释如下
2、怎么使用netty来进行通信?
接下来看一段简单的netty客户端的代码
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try{
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY,true)
.handler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("frameEncoder",new LengthFieldPrepender(4));
pipeline.addLast("decoder",new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("encode",new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast("myClient",new MyClient());
}
});
for(int i=0;i<10;i++){
ChannelFuture f = bootstrap.connect("127.0.0.1",6666).sync();
f.channel().writeAndFlush("my client send message>>>>>>>>>>>"+i);
f.channel().closeFuture().sync();
}
发现其最先创建的是NioEventLoopGroup,然后放入到Bootstrap驱动类中进行运行。Bootstrap中具体干了什么操作我们暂且不管,先来分析下这个NioEventLoopGroup是什么东西。
3、NioEventLoopGroup是什么
可以看到NioEventLoopGroup其实实现的是ScheduledExecutorService,也就是一个线程池。
接下来我们以NioEventLoopGroup的无参构造方法为入口,详细的看看在初始化的时候做了哪些操作
发现依次调用顺序如下 NioEventLoopGroup()——>this(0)——>this(nThreads, (Executor) null)——>this(nThreads, executor, SelectorProvider.provider())——>this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE)——>MultithreadEventLoopGroup(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject())——>MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args)——>MultithreadEventExecutorGroup(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args)
上面一段长长的流程就是在不断的调用重载构造方法和父类的构造方法,在进入上述标红构造方法中将出现具体操作,先上源码
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
}
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
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;
}
}
}
}
}
接下来分析下里面核心的几行代码
nThread,因为我们是无参构造,所以前期传入的是0,但是在父类构造方法中通过
static { DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt( "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2)); }
nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads
进行了赋值操作 nThreads = cpu的核心数*2
执行器,看名字说明是每个任务的执行者,它的executor就是通过线程工厂创建线程将task放入,然后start()
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
创建NioEventLoopGroup的child数组
children = new EventExecutor[nThreads];
children[i] = newChild(executor, args);
因为我们当前调用者是NioEventLoopGroup,所以newChild调用的是下面方法
@Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}
也就是children中存放的是根据nThread大小的NioEventLoop的数组。
chooser对象里面存储的也是children,通过chooser.next()得到下一个children中存储的NioEventLoop,在initAndRegister中需要用到
chooser = chooserFactory.newChooser(children);
以上就是NioEventLoopGroup的创建过程。