Netty in Action:EventLoop和线程模型
本章包含
线程模型概览
Event Loop的概念和实现
Task调度
实现详解
简单来说,线程模型定义了操作系统,编程语言,框架或者应用程序线程管理的关键部分。线程是如何,并且何时被创建,显然对代码的执行有很大的影响。因此,开发者需要理解不同线程模型中存在的权衡利弊。无论他们是直接为自己选择模型,还是通过用一种语言或者框架隐性地来选择模型,这一点都是毋庸置疑的。
在这一章我们会详细探讨Netty的线程模型。Netty线程模型很强大,不过用起来很简单。Netty总是一如既往地简化你的应用代码,最大化应用的性能和可维护性。我们还会讨论到我们选择Netty目前这个线程模型的整个过程。
如果你对Java并发API(java.util.concurrent)有一个大致的了解,你会感觉本章的讨论很清晰明了。如果你对这些概念不熟悉,或者需要再回忆下,Brian Goetz和其他人合著的《Java并发编程实战》是个很棒的资源。
7.1 线程模型概览
在这一小节我们会大体上介绍下线程模型,然后讨论下Netty过去和现在采用的线程模型,并且回顾下两种模型各自的优势和限制。
我们在本章开头提到的,一个线程模型决定了代码将如何被执行。因为我们必须始终防范并发执行可能带来的副作用,所以理解线程模型的真正含义是很重要的(还有单线程模型)。忽略这些事,仅仅希望获得最好的结果跟赌博没什么两样——如你所愿的机会很渺茫。
因为多核或者多CPU的电脑很普遍,现代应用程序大部分都采用复杂的多线程技术来充分利用系统资源。但是相比之下,在Java早期,我们的多线程策略只不过是按需要创建和启动新的Thread,来执行并发的工作任务单元,这个粗糙的策略在高负载下表现得非常糟糕。然后Java5引入了Executor API,通过线程缓存和复用,线程池极大地提高了性能。
基本的线程池模式描述如下:
- 从池中空闲的线程中选出一个,分配一个提交的task(一个Runnable的实现)
- 当task完成,线程返回池中,等待复用(下一次task分配)
这个模式如图7.1所示。
图7.1 Executor执行逻辑

相比为每个task都创建和销毁一个线程,将线程放入池中、复用线程是一次性能的提升。但是这个模型还是无法消除上下文切换带来的开销,而这一点会随着线程数量的增加变得明显,在高负载下会变得严重。此外,在一个项目的运行过程中,因为某个应用的整体复杂度和并发需求,其他线程相关的问题也会出现。
总之,多线程是复杂的。在下面的小节里,我们会看到Netty是如何帮助你简化它的。
7.2 EventLoop接口
运行task来处理一个连接在生命周期中产生的event,是任何一个网络框架的基本功能。其相应的编程结构通常被称为一个event loop, Netty采纳了这个名字,设计了接口io.netty.channel.EventLoop。
一个event loop的基本构想如下代码所示,代码中的每个task都是一个Runnable实例(如图7.1)
代码清单7.1 在一个event loop中执行task

首先,io.netty.util.concurrent包是基于JDK包java.util.concurrent创建的,以此来提供thread executor。其次,io.netty.channel中的类扩展了这两个包的一些接口,来和Channel的event相连接。类层次结构如图7.2所示。
图7.2 EventLoop 类层次结构

This chapter requires login to view full content. You are viewing a preview.
Login to View Full Content