mina 中的线程
在 mina简介 中提到,mina 是一个多线程的框架,本文就来看看 mina 中线程的使用。mina 中都是使用 java.util.concurrent.Executor 来使用线程的。
注意: 本文中所讨论的 mina 中的线程是针对基于 socket 的应用程序的,也就是说使用 SocketAcceptor 的程序,另外两种 IoAcceptor 的实现中对线程的使用可能相同,也可能不同,我并没有对它们做过多的研究。
在基于 SocketAcceptor 的应用程序中,运行过程中 mina 框架本身会有两种类型的线程在运行,一种是在 SocketAcceptor 中创建的用于监听并接收来自客户端请求的线程,还有一类线程是处理客户端与服务器端 I/O 的线程。
当调用 SocketAcceptor 的 bind 方法时,默认会创建一个名称前缀为 SocketAcceptor 的线程,该线程负责监听来自客户端的请求,如果接收到客户端的请求,它仅仅是为处理这个请求做好准备,而把具体处理请求以及 I/O 的任务代理给 SocketIoProcessor,让它去处理请求。这个准备过程主要是为接受到的请求创建一个 IoSession,并构建出 IoFilter 链,然后把准备好的数据以及来自客户端的请求交给 SocketIoProcessor 处理。通常 这类线程会针对每一次的 bind 调用创建一个新的线程。
请注意 前一节中的“通常 ” 二字,使用这两个字说明上述的行为不是绝对的。的确这不是绝对的,这取决于 SocketAcceptor 的字段 executor 的实现,可以通过构造方法来设置字段 executor 的值,executor 字段的类型为 java.util.concurrent.Executor。mina 默认是用 org.apache.mina.util.NewThreadExecutor,它会为每一个提交的任务创建一个新的线程。因为在 bind 方法中它会把实现监听客户端请求任务的 Runnable 提交到 executor 中去执行。注意千万不要使用一个不创建新线程而是在原线程中执行的 Executor,这会使程序无法监听客户端的请求,因为程序中的唯一线程会被 Selector.get() 方法所阻塞,详情可以查看 SocketAcceptor 类的源代码。
当 SocketAcceptor 收到了来自客户端的请求,它就会把此请求丢给 SocketIoProcessor 去处理,这会创建名称以 SocketAcceptorIoProcessor 为前缀的线程,mina 框架在这类线程中处理 I/O 发布并处理事件。这一类线程的数量可以通过 SocketAcceptor 的构造函数来设置。具体的值可以根据应用的具体需求来决定。
上述的两类线程是 mina 框架本身所创建的,如果你的应用每次处理请求的时间较长而又希望应用能够有较好的响应性,那么最好是把处理业务逻辑的任务放到一个新的线程中去执行,而不是在 mina 框架创建的线程中去执行。
mina 框架本身提供了一个过滤器 ExecutorFilter 来完成这样的任务,它会把在此之后的过滤器以及 IoHandler 中处理业务逻辑的代码放到一个新的线程中去执行。当 mina 框架中的第二类线程执行完此过滤器后就会立即返回,可以用于处理新的请求。如果不想使用此过滤器,还可以设置 mina 的线程模型来达到相同的效果,其实线程模型也是使用 ExecutorFilter 实现的。但需要注意的是,在 mina 2.0 版本中已经废弃了线程模型。
mina 框架中具体的如何使用线程可以查看它的源代码,本文只是一个简单地介绍,在 mina 网站的文档中也有一份针对 mina 1.x 版本中的线程模型的说明,请参见 http://mina.apache.org/configuring-thread-model.html 。