Mina的多线程模式——节选自设计文档
2010-05-21 19:49
211 查看
1.1
多线程模式
由于本项目使用的Apache Mina
的框架进行网络通信。当然其多线程模式也应该在
Mina
框架中体现出来。
为了理解多线程模式,首先要了解
Mina
的运作方式。
1.1.1
Mina
的通信过程
此次便于解说,假设客户端也是采用了Mina
框架来进行,实际上本项目的客户端只是简单的使用了
windows
的
Socket
通信。在当前假设下,其通信过程如下图
16
所示。
图
16 Apache Mina
的通信过程
本项目只关注服务端,其服务端的通信过程如下:
1
、通过
SocketAcceptor
同客户端建立连接;
2
、链接建立之后
I/O
的读写交给了
I/O Processor
线程,
I/O Processor
是多线程的;
3
、通过
I/O Processor
读取的数据经过
IoFilterChain
里所有配置的
IoFilter
,
IoFilter
进行消息的过滤,格式的转换,在这个层面可以制定一些自定义的协议;
4
、最后
IoFilter
将数据交给
Handler
进行业务处理,完成了整个读取的过程;
5
、写入过程也是类似,只是刚好倒过来,通过
IoSession.write
写出数据,然后
Handler
进行写入的业务处理,处理完成后交给
IoFilterChain
,进行消息过滤和协议的转换,最后通过
I/O Processor
将数据写出到
socket
通道。
1.1.2
Mina
的多级线程池
服务端的一个简化过程如下图17
所示:
图
17
多级线程池
在基于
SocketAcceptor
的应用程序中,运行过程中
Mina
框架本身会有两种类型的线程在运行,一种是在
SocketAcceptor
中创建的用于监听并接收来自客户端请求的线程,还有一类线程是处理客户端与服务器端
I/O
的线程,即
Processor
的处理线程。后面还有第三类,就是过滤器层的线程。这个多级的概念后面你会体会到,
Acceptor
是一级线程池,而
Processor
的线程池主要通过
ExecutorFileter
进行添加,当然可以添加多个层次的线程池。下面逐层进行讲解。
1
、第一类线程池:
当调用
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
的构造函数来设置。具体的值可以根据应用的具体需求来决定。
作为
I/O
真正处理的线程,存在于服务器端和客户端,用来处理
I/O
的读写操作,线程的数量是可以配置的,默认最大数量是
CPU
个数
+1
。
在服务器端中,在创建
SocketAcceptor
的时候指定
ProcessorCount
。
SocketAcceptor acceptor =
new SocketAcceptor(Runtime.getRuntime().availableProcessors() + 1, Executors.newCachedThreadPool());
NioProcessor
虽然是多线程,但是对与一个连接的时候业务处理只会使用一个线程进行处理(
Processor
线程对于一个客户端连接只使用一个线程
NioProcessor-n
)如果
handler
的业务比较耗时,会导致
NioProcessor
线程堵塞
,在
2
个客户端同时连接上来的时候会创建第
2
个(前提是第
1
个
NioProcessor
正在忙),创建的最大数量由
Acceptor
构造方法的时候指定。如果:一个客户端连接同服务器端有很多通信,并且
I/O
的开销不大,但是
Handler
处理的业务时间比较长,那么需要采用独立的线程模式,在
FilterChain
的最后增加一个
ExecutorFitler
,这个就是第三类线程池了。
第三类线程池:
上述的两类线程是
mina
框架本身所创建的,如果你的应用每次处理请求的时间较长而又希望应用能够有较好的响应性,那么最好是把处理业务逻辑的任务放到一个新的线程中去执行,而不是在
mina
框架创建的线程中去执行。
mina
框架本身提供了一个过滤器
ExecutorFilter
来完成这样的任务,它会把在此之后的过滤器以及
IoHandler
中处理业务逻辑的代码放到一个新的线程中去执行。当
mina
框架中的第二类线程执行完此过滤器后就会立即返回,可以用于处理新的请求。如果不想使用此过滤器,还可以设置
mina
的线程模型来达到相同的效果,其实线程模型也是使用
ExecutorFilter
实现的。但需要注意的是,在
mina 2.0
版本中已经废弃了线程模型。
使用类这三次线程池,性能可以得到保证了,在本项目中,主要配置了第二类线程池和第三类线程池。第二类线程池在新建
NioAcceptor
对象(以建立
TCP
监听服务器为例)时候,在其构造函数中体现,而这个数值需要多次测试来设定,其测试方法在国外网站有完整表述,请自行
;第三类线程池设定在
Apache Mina
的过滤器层,一般而言只需要设置一层,设置在最消耗时间的业务前面,如比较复杂的解码,或者是数据库访问模块。
关于共享线程池问题,
Apache Mina
有个官方说法:你可以想让
IoServices
和
ExecutorFilters
共享一个线程池,而不是一家一个。这个是不禁止的,但是会出现很多问题,在这种情况下,除非你为
IoServices
建立一个缓冲线程池。
本人尚未考究。
相关文章推荐
- Mina的多线程模式——节选自设计文档
- Android多线程设计模式---wait()和notify()机制
- 【设计模式】5. 单例模式(以及多线程、无序写入、volatile对单例的影响)
- day06static关键字,main函数,帮助文档的制作,静态代码块,对象的初始化过程,单例设计模式
- 胖虎白话学习设计模式之多线程与单例模式设计模式(Singleton)
- Java自学笔记(第六天)-static-类变量-对象变量-javadoc文档-static代码块-单例设计模式
- 黑马程序员_单例设计模式&多线程
- 黑马程序员_多线程中的Lock锁,死锁以及单例设计模式分析
- 设计模式与多线程——用命令模式来设计多线程架构
- 黑马程序员_静态方法,java文档制作和单例设计模式
- java笔记-面向对象-匿名对象、说明文档、单例设计模式
- 多线程设计模式-Active Object
- 【多线程高并发】多线程的设计模式
- Java多线程编程6--单例模式与多线程--单例模式设计详解1
- 多线程编程的设计模式 临界区模式(一)
- 多线程设计模式Future、Master-Worker和生产者-消费者模型
- 网络爬虫中的那些多线程设计模式
- 黑马程序员——多线程和单例设计模式
- 多线程的 pipeline 设计模式
- 多线程、内存、设计模式