netty探索之旅七

前面我们分析了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线程可以同时绑定到多个客户端连接中。

[color=red]为什么不让一个特定的线程池来处理acceptor喃???[/color]

单线程对应在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初始化过程:
[img]http://dl2.iteye.com/upload/attachment/0123/5033/b956286a-61e8-3d8c-9c27-c2d979d33c3c.png[/img]

1,NioEventLoopGroup内部维护一个类型为EventExecutor数组(变量:children),构造了一个线程池
2,调用newChild抽象方法来初始化children数组
3,抽象方法newChild在 NioEventLoopGroup 中实现的,返回一个NioEventLoop实例

NioEventLoop:
继承关系:NioEventLoop-->SingleThreadEventLoop-->SingleThreadEventExecutor-->AbstractScheduledEventExecutor。[color=blue]SingleThreadEventExecutor是netty中对本地线程的抽象,它内部有一个Thread thread属性, 存储了一个本地Java线程。一个NioEventLoop和一个线程绑定.[/color]

[color=blue]在AbstractScheduledEventExecutor中,实现了schedule的功能,我们可以通过调用NioEventLoop实例的schedule方法来运行一些定时任务。
在SingleThreadEventLoop中实现了任务队列的功能,我们可以通过调用NioEventLoop实例的execute方法来向任务队列中添加一个task,由NioEventLoop进行调度执行。
NioEventLoop肩负着两种任务:第一作为IO线程,执行与channel的IO操作,包括调用select等待就绪的IO事件,读写数据,数据的处理。第二作为任务队列,执行队列中的任务[/color]

关于channel和EventLoop是怎么关联起来的可以看看
[url]http://jishuaige.iteye.com/blog/2356798[/url]---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所对应的线程就启动了。

[color=blue]当EventLoop.execute第一次被调用时,就会触发startThread()的调用,进而EventLoop所对应的Java线程的启动。[/color]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值