文章目录
JDK中的线程池
线程池的基本操作就是从线程池的空闲线程列表中选择一个Thread,并且指派它去执行一个已经提交的任务;当任务完成之后,就这个线程返回给线程池,使其可以重用。
缺点就是:并不能消除由上下文切换所带来的开销。
EventLoop接口
下图中所示的 是EventLoop的类层次结构
在这个模型中,一个EventLoop 将由一个永远都不会改变的Thread 驱动,同时任务(Runnable 或者Callable)可以直接提交给EventLoop 实现,以立即执行或者调度执行。根据配置和可用核心的不同,可能会创建多个EventLoop 实例用以优化资源的使用,并且单个EventLoop 可能会被指派用于服务多个Channel。
Netty4中的I/O和事件处理
由I/O 操作触发的事件将流经安装了一个或者多个ChannelHandler 的ChannelPipeline。传播这些事件的方法调用可以随后被Channel-Handler 所拦截,并且可以按需地处理事件。
任务调度
JDK中的任务调度API
JDK 提供了java.util.concurrent 包,它定义了interface ScheduledExecutorService。
这里给出两个EventLoop调度任务的两个例子
60秒之后执行
/**
* eventLoop60秒之后执行指定方法
* ,这里只是输出了一行文字
* @param channel
*/
public static void schedule(Channel channel) {
channel.eventLoop().schedule(new Runnable() {
@Override
public void run() {
System.out.println("60 Seconds later, I run");
}
},60, TimeUnit.SECONDS);
}
60秒之后执行,并且每隔60秒执行
/**
* 调度在60秒之后进行,而且每60秒执行一次
* @param channel
*/
public static void scheduleAtFixedRate(Channel channel) {
ScheduledFuture<?> scheduledFuture = channel.eventLoop().scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("Run Every 60 Seconds");
}
}, 60, 60, TimeUnit.SECONDS);
// 这个表示是否终止
// scheduledFuture.cancel(true);
}
EventLoop实现细节
这里说的是Netty的线程模型和任务调度实现的内容。
线程管理
如果(当前)调用线程正是支撑EventLoop 的线程,那么所提交的代码块将会被(直接)执行。否则,EventLoop 将调度该任务以便稍后执行,并将它放入到内部队列中。当EventLoop下次处理它的事件时,它会执行队列中的那些任务/事件。每个EventLoop 都有它自已的任务队列,独立于任何其他的EventLoop。
EventLoop线程的分配
服务于Channel 的I/O 和事件的EventLoop 包含在EventLoopGroup 中。根据不同的传输实现,EventLoop 的创建和分配方式也不同。
异步传输
异步传输实现只使用了少量的EventLoop(以及和它们相关联的Thread),而且在当前的线程模型中,它们可能会被多个Channel 所共享。这使得可以通过尽可能少量的Thread 来支撑大量的Channel,而不是每个Channel 分配一个Thread。
显示了一个EventLoopGroup,它具有3 个固定大小的EventLoop(每个EventLoop都由一个Thread 支撑)。在创建EventLoopGroup 时就直接分配了EventLoop(以及支撑它们的Thread),以确保在需要时它们是可用的。
EventLoopGroup 负责为每个新创建的Channel 分配一个EventLoop。在当前实现中,使用顺序循环(round-robin)的方式进行分配以获取一个均衡的分布,并且相同的EventLoop可能会被分配给多个Channel。一旦一个Channel 被分配给一个EventLoop,它将在它的整个生命周期中都使用这个EventLoop(以及相关联的Thread)。
注意:需要注意的是,EventLoop 的分配方式对ThreadLocal 的使用的影响。因为一个EventLoop 通常会被用于支撑多个Channel,所以对于所有相关联的Channel 来说,ThreadLocal 都将是一样的。
阻塞传输
这里每一个Channel 都将被分配给一个EventLoop(以及它的Thread)。
,正如同之前一样,得到的保证是每个Channel 的I/O 事件都将只会被一个Thread(用于支撑该Channel 的EventLoop 的那个Thread)处理。