线程模型确定了代码的执行方式
- 早起Java语言中,我们使用多 线程处理的主要方式无非是按需创建和启动新的 Thread 来执行并发的任务单元——一种在高 负载下工作得很差的原始方式。
- 。Java 5 随后引入了 Executor API,其线程池通过缓存和重用 Thread极大地提高了性能。
基本的线程池化模式
- 从池的空闲线程列表中选择一个 Thread,并且指派它去运行一个已提交的任务(一个 Runnable的实现); - 当任务完成时,将该Thread返回给该列表,使其可被重用。
事件/任务的执行顺序 事件和任务是以先进先出(FIFO)的顺序执行的。这样可以通过保证字 节内容总是按正确的顺序被处理,消除潜在的数据损坏的可能性
EventLoop 接口
运行任务来处理在连接的生命周期内发生的事件是任何网络框架的基本功能。 – 事件循环
- 在Netty 4 中,所有的I/O操作和事件都由已经被分配给了 EventLoop的那个Thread来处理
- 在以前的版本中所使用的线程模型只保证了入站(之前称为上游)事件会在所谓的 I/O 线程 (对应于 Netty 4 中的EventLoop)中执行。所有的出站(下游)事件都由调用线程处理,其可 能是 I/O 线程也可能是别的线程。
需要在ChannelHandler中对出站事件进行仔细的同步,不可能保证多个线程 不会在同一时刻尝试访问出站事件.
EventLoop的任务调度
- Java5之前,使用java.util.Timer
-
Java5之后,使用java.util.concurrent包提供的ScheduleExecutorService
- 高负载下会有性能负担,过多的线程上下文切换
ScheduledExecutorService executor = Executors.newScheduledThreadPool(10); ScheduledFuture<?> future = executor.schedule(new Runnable() { @Override public void run() { System.out.println("60 seconds later"); } },60, TimeUnit.SECONDS);
使用EventLoop在netty中调度任务
//执行一次,若每隔60秒执行一次使用scheduleAtFixedRate,完全继承了ScheduledExecutorService的特性。 Channel ch = ... ScheduledFuture<?> future = ch.eventLoop().schedule( new Runnable() { @Override public void run() { System.out.println("60 seconds later"); } }, 60, TimeUnit.SECONDS);
用于非阻塞传输(NIO和AIO)的EventLoop的分配方式
用于阻塞(OIO)的分配方式