前面我们分析了Pipeline,还有一个东西值得我们去研究研究,那就是EventLoop。哈哈!我们继续吧!
不管是在客户端还是服务端,在netty启动的时候,都会指定EventLoopGroup,当然用的最多的就是NIO,所以都会指定NioEventLoopGroup。那么这个NioEventLoopGroup在Nnetty中是扮演什么角色的喃!netty是基于Reactor模型的一个实现,那么我们先简单的说明一下Reactor的线程模型。
单线程模型:
所有的acceptor处理和handler处理都在同一个线程中。这种模式的坏处就是显而易见的了,当一个handler阻塞时,会导致所有的handler都不能执行,同时整个服务也不会接受新请求。
多线程模型:
与单线程模型的区别在于,把acceptor让一个独立的线程来处理,后面有一组NIO的线程池来处理客户端连接的IO操作。
特点:
有一个专门的acceptor线程用于监听客户端的TCP连接请求。
客户端连接的IO操作由一个特定的NIO线程池负责. 每个客户端连接都与一个特定的NIO线程绑定, 因此在这个客户端连接中的所有IO操作都是在同一个线程中完成的.
客户端连接有很多,但是NIO线程池中的线程数是较少的,因此一个NIO线程可以同时绑定到多个客户端连接中。
为什么不让一个特定的线程池来处理acceptor喃???
单线程对应在netty中的表现是什么样子的喃
看一个例子:
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup)
.channel(NioServerSocketChannel.class)
........
NioEventLoopGroup构造参数是1,表明线程池的大小是1,接着调用ServerBootstrap的group(bossGroup)方法。接着我们看看ServerBootstrap的group(bossGroup)方法的实现:
public ServerBootstrap group(EventLoopGroup group) {
return group(group, group);
}
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;
}
很容易我们看出来了,传入一个group的时候,我们的bossGroup和workerGroup是同一个NioEventLoopGroup。并且这个NioEventLoopGroup只有一个线程,这样acceptor和后续的所有客户端连接的IO操作都在这个线程里面了,这个就是对应Reactor的单线程模型。
再看一个例子:
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
........
bossGroup只有一个线程,workerGroup的线程是CPU核心数乘以2。这样就是Reactor的多线程模式。
下面来看看NioEventLoopGroup和NioEventLoop初始化过程:
1,NioEventLoopGroup内部维护一个类型为EventExecutor数组(变量:children),构造了一个线程池
2,调用newChild抽象方法来初始化children数组
3,抽象方法newChild在 NioEventLoopGroup 中实现的,返回一个NioEventLoop实例
NioEventLoop:
继承关系:NioEventLoop-->SingleThreadEventLoop-->SingleThreadEventExecutor-->AbstractScheduledEventExecutor。
SingleThreadEventExecutor是netty中对本地线程的抽象,它内部有一个Thread thread属性, 存储了一个本地Java线程。一个NioEventLoop和一个线程绑定.
在AbstractScheduledEventExecutor中,实现了schedule的功能,我们可以通过调用NioEventLoop实例的schedule方法来运行一些定时任务。
在SingleThreadEventLoop中实现了任务队列的功能,我们可以通过调用NioEventLoop实例的execute方法来向任务队列中添加一个task,由NioEventLoop进行调度执行。
NioEventLoop肩负着两种任务:第一作为IO线程,执行与channel的IO操作,包括调用select等待就绪的IO事件,读写数据,数据的处理。第二作为任务队列,执行队列中的任务
关于channel和EventLoop是怎么关联起来的可以看看
http://jishuaige.iteye.com/blog/2356798---netty探索之旅三
EventLoop的启动
NioEventLoop的启动,其实就是NioEventLoop所绑定的本地Java线程的启动。
在NioEventLoop的父类SingleThreadEventExecutor中
private void startThread() {
if (STATE_UPDATER.get(this) == ST_NOT_STARTED) {
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
thread.start();
}
}
}
这个方法调用NioEventLoop所绑定的本地Java线程的start方法,启动线程。
跟着这个方法被调用轨迹走:SingleThreadEventExecutor中的execute
public void execute(Runnable task) {
if (task == null) {
throw new NullPointerException("task");
}
boolean inEventLoop = inEventLoop();
if (inEventLoop) {
addTask(task);
} else {
startThread();
addTask(task);
if (isShutdown() && removeTask(task)) {
reject();
}
}
if (!addTaskWakesUp && wakesUpForTask(task)) {
wakeup(inEventLoop);
}
}
在第三节我们分析channel注册的时候,在AbstractUnsafe.register有这段代码:
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
.....................
eventLoop.execute就是在调用上面的SingleThreadEventExecutor.execute,这样NioEventLoop所对应的线程就启动了。
当EventLoop.execute第一次被调用时,就会触发startThread()的调用,进而EventLoop所对应的Java线程的启动。

- 大小: 28.8 KB
分享到:
相关推荐
这次分享为你带来了丰富的Java语言游戏项目实战资源,让你在实践中深入掌握Java语言,并开启游戏开发之旅。资源包中包括: 游戏项目代码:精心挑选了多个经典的小游戏项目,如猜数字、坦克大战等,每个项目都有完整...
这次分享为你带来了丰富的Java语言游戏项目实战资源,让你在实践中深入掌握Java语言,并开启游戏开发之旅。资源包中包括: 游戏项目代码:精心挑选了多个经典的小游戏项目,如猜数字、坦克大战等,每个项目都有完整...
这次分享为你带来了丰富的Java语言游戏项目实战资源,让你在实践中深入掌握Java语言,并开启游戏开发之旅。资源包中包括: 游戏项目代码:精心挑选了多个经典的小游戏项目,如猜数字、坦克大战等,每个项目都有完整...
这次分享为你带来了丰富的Java语言游戏项目实战资源,让你在实践中深入掌握Java语言,并开启游戏开发之旅。资源包中包括: 游戏项目代码:精心挑选了多个经典的小游戏项目,如猜数字、坦克大战等,每个项目都有完整...
这次分享为你带来了丰富的Java语言游戏项目实战资源,让你在实践中深入掌握Java语言,并开启游戏开发之旅。资源包中包括: 游戏项目代码:精心挑选了多个经典的小游戏项目,如猜数字、坦克大战等,每个项目都有完整...
《Zbynek的Netty POF实验与概念证明——深入理解Java网络编程》 在Java领域,Netty作为一款高性能、异步事件驱动的网络应用...对于任何对Java网络编程感兴趣的人来说,深入研究这个项目都将是一次富有价值的学习之旅。
这次分享为你带来了丰富的Java语言游戏项目实战资源,让你在实践中深入掌握Java语言,并开启游戏开发之旅。资源包中包括: 游戏项目代码:精心挑选了多个经典的小游戏项目,如猜数字、坦克大战等,每个项目都有完整...
总结,Dubbo的源码解析是一场深入到服务治理核心的探索之旅,通过对Provider、Consumer、Registry、负载均衡、服务治理等模块的剖析,我们可以更清晰地理解Dubbo如何高效、稳定地支撑大规模分布式系统的构建。...
【标题】:深入理解JDK源码 在Java开发领域,深入阅读JDK源码是提升技术水平...总之,JDK源码阅读是一场深度技术探索之旅,它将帮助我们揭开Java语言的神秘面纱,提升我们的编程技艺,使我们成为更优秀的Java开发者。