在Mina的使用中,线程池的配置一个比较关键的环节,同时它也是Mina性能提高的一个有效的方法,在Mina的2.0以上版本中已经不再需要对Mina线程池的配置了,本系列文章都是基于当前的稳定版本Mina 1.1.7版来进行讲述的,Mina的2.0以上版本现在还都是M(millestone,即里程碑)版的,在1.5版本上2.0M版为稳定版本,但是在1.5+以上则为非稳定版本,所以,为了更好的进行讨论和学习,还是基于Mina 1.1.7版本进行讨论,如果使用Mina 2.0进行开发要注意JDK的版本问题,当然如果有能力的话也可以自行修改和编译Mina的2.0版本,这里对此就不再多说,使用2.0版本的同学可以不用理会本文的内容。
上面的内容都是基于Apache Mina提供的文档讲述,如有需要,请自行查找相关资料,在此不再赘述。
下面开始对Mina的线程模型的配置、使用、及ExcutorFilter的基本原理进行简单的讲解。
配置Mina的三种工作线程
在Mina的NIO模式中有三种I/O工作线程(这三种线程模型只在NIO Socket中有效,在NIO数据包和虚拟管道中没有,也不需要配置):
Acceptor thread
该线程的作用是接收客户端的连接,并将客户端的连接导入到I/O processor线程模型中。所谓的I/O processor线程模型就是Mina的I/O processor thread。Acceptor thread在调用了Acceptor.bind()方法后启动。每个Acceptor只能创建一个Acceptor thread,该线程模型不能配置,它由Mina自身提供。
Connector thread
该线程模型是客户端的连接线程模型,它的作用和Acceptor thread类似,它将客户端与服务器的连接导入到I/O processor线程模型中。同样地,该线程模型也是由Mina的客户端自动创建,该线程模型也不能进行配置。
I/O processor thread
该线程模型的主要作用就行接收和发送数据,所有的IO操作在服务器与客户端的连接建立后,所有的数据的接收和发送都是有该线程模型来负责的,知道客户端与服务器的连接关闭,该线程模型才停止工作。该线程模型可以由程序员根据需要进行配置。该线程模型默认的线程的数量为cpu的核数+1。若你的cpu为双核的,则你的I/O processor 线程的最大数量为3,同理若你的若你的cpu为四核的,那么你的I/O processor 线程的最大数量为5。
由上面的内容我们可以知道在Mina中可以配置的线程数量只有I/O processor,对于每个IoService再创建其实例的时候可以配置该IoService的I/O processor的线程数量。在SokcetConnector和SocketAccpetor中I/O Processor的数量是由CPU的核数+1来决定的。
他们的配置方式如下:
/***
* 配置SocketAcceptor监听器的I/O Processor的线程的数量,
* 此处的I/O Processor的线程数量由CPU的核数决定,但Acceptor
* 的线程数量只有一个,也就是接收客户端连接的线程数只有一个,
* Acceptor的线程数量不能配置。
* */
SocketAcceptor acceptor = new SocketAcceptor(Runtime.getRuntime()
.availableProcessors() + 1, Executors.newCachedThreadPool());
/***
* 配置SocketConnector监听器的I/O Processor的线程的数量,
* 此处的I/O Processor的线程数量由CPU的核数决定,但SocketConnector
* 的线程数量只有一个,也就是接收客户端连接的线程数只有一个,
* SocketConnector的线程数量不能配置。
* */
SocketConnector connector = new SocketConnector(Runtime.getRuntime()
.availableProcessors() + 1, Executors.newCachedThreadPool());
在上面的配置比较难以理解的地方就是Runtime.getRuntime().availableProcessors() + 1,它的意思就是由JVM根据系统的情况(即CPU的核数)来决定IO Processor的线程的数量。虽然这个线程的数量是在SocketAcceptor /SocketConnector 的构造器中进行的,但是对于SocketAcceptor /SocketConnector自身的线程没有影响,SocketAcceptor /SocketConnector的线程数量仍然为1。为SocketAcceptor /SocketConnector本身就封装了IO Processor,SocketAcceptor /SocketConnector只是由一个单独的线程来负责接收外部连接/向外部请求建立连接,当连接建立后,SocketAcceptor /SocketConnector会把数据收发的任务转交I/O Processor的线程。这个在本系列文章的《IoFilter和IoHandler的区别和联系》中的图示中可以看。
图中清晰的显示了IO Processor就是位于IoService和IoFilter之间,IoService负责和外部建立连接,而IoFilter则负责处理接收到的数据,IoProcessor则负责数据的收发工作。
关于配置IO Processor的线程数量还有一种比较“笨”的办法,那就一个一个试,你可以根据你的PC的硬件情况从1开始,每次加1,然后得出IO Processor的最佳的线程的数量。但是这种方式个人建议最好不要用了,上面的方法足矣。配置方法如下:
//从1--N开始尝试,N的最大数量为CPU核数+1
SocketAcceptor acceptor = new SocketAcceptor(N, Executors.newCachedThreadPool());
为Mina的IoFilterChain添加线程池
在Mina的API中提供了一个ExecutorFilter,该线程池实现了IoFilter接口,它可以作为一个IoFilter添加到IoFilterChain中,它的作用就是将I/O Processor中的事件通过其自身封装的一个线程池来转发到下一个过滤器中。在没有添加该线程模型时,I/O Processor的事件是通过方法来触发的,然后转发给IoHandler。在没有添加该线程池的时候,所有的事件都是在单线程模式下运行的,也就是说有的事件和处理(IO Processor,IoHandler,IoFilter)都是运行在同一个线程上,这个线程就是IO Processor的线程,但是这个线程的数量受到CPU核数的影响,因此系统的性能也直接受CPU核数的影响。
比较复杂的应用一般都会用到该线程池,你可以根据你的需求在IoFilterchain中你可以添加任意数量的线程池,这些线程池可以组合成一个事件驱动(SEDA)的处理模型。对于一般的应用来说不是线程的数量越多越好,线程的数量越多可能会加剧CPU切换线程所耗费的时间,反而会影响系统的性能,因此,线程的数量需要根据实际的需要由小到大,逐步添加,知道找到适合你系统的最佳线程的数量。ExcutorFilter的配置过程如下:
SocketAcceptor acceptor = ...;
DefaultIoFilterChainBuilder filterChainBuilder = acceptor.getDefaultConfig().getFilterChain();
filterChainBuilder.addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool());
在配置该线程池的时候需要注意的一个问题是,当你使用自定的ProtocolCodecFactory时候一定要将线程池配置在该过滤器之后,如下所示:
DefaultIoFilterChainBuilder filterChainBuilder = acceptor.getDefaultConfig().getFilterChain();
// 和CPU绑定的操作配置在过滤器的前面
filterChainBuilder.addLast("codec", new ProtocolCodecFactory(...));
// 添加线程池
filterChainBuilder.addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool());
因为你自己实现的ProtocolCodecFactory直接读取和转换的是二进制数据,这些数据都是由和CPU绑定的I/O Processor来读取和发送的,因此为了不影响系统的性能,也应该将数据的编解码操作绑定到I/O Processor线程中,因为在Java中创建和线程切换都是比较耗资源的,因此建议将ProtocolCodecFactory配置在ExecutorFilter的前面。关于ProtocolCodecFactory详细讲述会在后续的文档中给出,此处就不多说了。
最后给出一个服务器线程模型完整配置的例子,该例子和KFCClient一起配置使用,详细代码在附件中,此处只给出代码的主要部分:
SocketAddress address = new InetSocketAddress("localhost", 4321);
/***
* 配置SocketAcceptor监听器的I/O Processor的线程的数量, 此处的I/O
* Processor的线程数量由CPU的核数决定,但Acceptor 的线程数量只有一个,也就是接收客户端连接的线程数只有一个,
* Acceptor的线程数量不能配置。
* */
IoAcceptor acceptor = new SocketAcceptor(Runtime.getRuntime()
.availableProcessors() + 1, Executors.newCachedThreadPool());
acceptor.getDefaultConfig().setThreadModel(ThreadModel.MANUAL);
// 配置数据的编解码器
acceptor.getDefaultConfig().getFilterChain().addLast("codec",
new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
// 此处为你自己实现的编解码器
// config.getFilterChain().addLast("codec", new
// ProtocolCodecFactory(...));
// 为IoFilterChain添加线程池
acceptor.getDefaultConfig().getFilterChain().addLast("threadPool",
new ExecutorFilter(Executors.newCachedThreadPool()));
acceptor.getDefaultConfig().getFilterChain().addLast("logger",
new LoggingFilter());
// 绑定服务器端口
acceptor.bind(address, new KFCFoodPriceHandler());
System.out.println(" 服务器开始在 8000 端口监听 .......");
// ==========================================//
// 此处为客户端的I/O Processor线程数的配置,你可以模仿 //
// IoAcceptor配置来实现 //
// ==========================================//
/***
* 配置SocketConnector监听器的I/O Processor的线程的数量, 此处的I/O
* Processor的线程数量由CPU的核数决定,但SocketConnector
* 的线程数量只有一个,也就是接收客户端连接的线程数只有一个, SocketConnector的线程数量不能配置。
* */
// SocketConnector connector = new SocketConnector(Runtime.getRuntime()
// .availableProcessors() + 1, Executors.newCachedThreadPool());
}
分享到:
相关推荐
在这个深入理解Apache Mina的第五部分中,我们将关注Mina的线程模型配置,这是优化性能和管理资源的关键方面。 在Mina的非阻塞I/O(NIO)模式下,存在三种主要的工作线程,它们在NIO Socket中起到不同的作用: 1. ...
深入理解Apache_Mina_(1)----_Mina的几个类 ...深入理解Apache_Mina_(5)----_配置Mina的线程模型 深入理解Apache_Mina_(6)----_Java_Nio_ByteBuffer与Mina_ByteBuffer的区别(类图) 相信你们也愿意去下载更有价值的东西
### Apache MINA线程模型配置详解 #### 一、线程模型配置介绍 Apache MINA 是一个用于构建网络应用程序的高性能、高可靠性的框架。它提供了丰富的功能来简化网络编程,包括TCP/IP 和 UDP/IP 协议的支持。线程模型...
7. **线程模型**:MINA提供了多种线程模型,如单线程、多线程以及NIO线程池,开发者可以根据实际需求选择最适合的模型。 8. **易于调试和监控**:MINA提供了详细的日志记录和统计功能,帮助开发者更好地理解和优化...
Apache MINA(Multipurpose Infrastructure for Network Applications)是一个高性能、异步事件驱动的网络应用程序框架,主要用Java语言编写。MINA旨在简化开发高效且可扩展的网络应用,如服务器端和客户端,支持TCP...
在“apache-mina-2.0.21-src.zip”这个压缩包中,包含了Apache Mina 2.0.21的源代码,这为我们提供了深入理解其内部工作原理的机会。 Apache Mina的核心特性包括: 1. **异步通信**:Mina基于Java NIO(非阻塞I/O...
5. **Source Code**:源代码可以帮助开发者深入理解MINA的工作原理,对其进行调试或扩展,同时也方便学习MINA的优秀设计和编程实践。 使用这个压缩包,开发者可以直接将MINA库引入到项目中,利用其强大的功能进行...
本资料集合对Apache Mina进行了深入探讨,涵盖了Mina的关键组件和概念,包括IoFilter、IoHandler、ByteBuffer以及线程模型等。 1. **IoFilter与IoHandler**: IoFilter是Mina中的过滤器机制,它允许在数据传输过程...
4. **源码**:如果你解压后发现有源代码,这将允许你深入理解MINA的工作原理,对于想要定制或扩展MINA功能的开发者来说非常有价值。 5. **构建文件**:可能会包含Maven的pom.xml文件,这是一个项目对象模型,用于...
Apache Mina是一个开源项目,主要用于构建高性能、高可用性的网络通信应用。它的全名是Apache MINA (Multipurpose Infrastructure for Network Applications),它提供了一个统一的API,使得开发者能够轻松地开发出...
5. **多线程与线程池**:MINA内部使用了线程池来处理网络事件,可以根据需求配置线程池大小,以平衡资源消耗和响应速度。 6. **缓冲区(Buffer)操作**:MINA提供了自己的缓冲区类,可以高效地处理字节流。缓冲区...
为了使用Apache MINA,你需要了解Java编程语言,理解I/O模型和网络协议,然后可以通过阅读MINA的官方文档,学习如何配置和使用过滤器链,以及如何编写事件处理器。此外,还可以参考提供的示例代码来快速上手。 总结...
Mina提供灵活的线程模型配置,如NIO多路复用器、简单的线程池或自定义线程模型。根据应用场景,选择合适的线程模型可以优化性能,例如在高并发场景下,通常会选择能有效利用系统资源的模型。 5. **状态机** Mina...
Apache MINA(Multipurpose Infrastructure for Network Applications)是一个Java框架,专为开发高性能和高度可扩展的网络应用程序而设计。MINA 提供了一种抽象层,允许开发者独立于传输协议(如TCP/IP或UDP/IP)来...
为了充分理解和有效地使用Apache Mina Server 2.0,开发者应具备以下基础知识: - **JAVA IO**:理解基本的输入输出流,包括字节流和字符流。 - **JAVA NIO**:了解非阻塞I/O的概念,包括选择器(Selectors)和通道...
5. **数据编码与解码**:Mina提供了多种编码器和解码器,如ByteToMessageDecoder和MessageToByteEncoder,用于将应用程序的数据转换为适合在网络上传输的字节流,以及将接收到的字节流还原为应用程序能理解的数据。...
《mina-1.1.7.zip:Java开源通信框架详解》 mina,全称为Apache MINA(Multipurpose Infrastructure for Network Applications),是一个用Java...通过深入理解和实践MINA,开发者能够构建出高效、可扩展的网络应用。
mina-transport-apr-2.0.7.jar是MINA对Apache Portable Runtime (APR)的支持,APR是一个库,提供了操作系统级别的接口,如socket和线程,可以提升MINA在某些平台上的性能。 mina-integration-jmx-2.0.7.jar提供了...