深入理解 Apache Mina ---- 配置 Mina 的线程模型


深入理解 Apache Mina ---- Mina 的ByteBuffer Author:中國壹石頭 ---------------------------------------------------------------------------------------------------------------------- What we call human nature is actually human habbit . 深 入 理解 Apache Mina ---- 配置Mina 的 线程模型 在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 Mina Mina 的三种工 作线 程 的三种工 作线 程 的三种工 作线 程 的三种工 作线 程 在Mina 的NIO模式 中有 三种 I/O 工作 线程 (这 三种线 程模 型只在 NIO Socket 中有 效, 在 NIO数据 包和 虚拟 管道中 没有 ,也 不需要 配置 ) : (1)Acceptor thread 该线程的作用是接收客户端的连接,并将客户端的连接导入到 I/O processor线程模型中。所谓的 I/O processor线程模型就是 Mina 的I/O processor thread。Acceptor thread在调用了 Acceptor.bind()方法后 启动。每个 Acceptor只能创建一个 Acceptor thread,该线程模型不能配置,它由 Mina 自身提供。 (2)Connector thread 该线程模型是客户端的连接线程模型,它的作用和 Acceptor thread类似,它将客户端与服务器的连接导入 到I/O processor线程模型中。同样地,该线程模型也是由 Mina 的客户端自动创建,该线程模型也不能进 行配置。 (3)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 * 的线程 数量只有一 个, 也就 是 接收 客户端 连 接的线程 数只有 一个, 深入理解 Apache Mina ---- Mina 的ByteBuffer Author:中國壹石頭 ---------------------------------------------------------------------------------------------------------------------- What we call human nature is actually human habbit . 在上 面的 配置 比较难 以理 解的 地方就是 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的最 佳的 线程 的数 量。 但是 这种 方式 个人建 议最 好不 要用了 ,上 面的 方法足 矣。 配置 方法如 下: (二) (二) (二) (二) 为为为为Mina Mina Mina Mina 的的的的IoFilterChainIoFilterChainIoFilterChainIoFilterChain添加 线程池 添加 线程池 添加 线程池 添加 线程池 在Mina 的API 中提 供了 一个 ExecutorFilter,该 线程 池实 现了 IoFilter 接口 ,它 可以 作为一 * Acceptor 的线程 数量不能 配 置。 **/ SocketAcceptor acceptor = new new new new SocketAcceptor(Run time. getRuntime () .availableProcessors() + 1, Executors.new Cac hedThreadPool ()); /*** * 配置 SocketConnector 监听器的 I/O Processor 的线程的数 量 , * 此处的 I/O Processor 的线程 数量由 CPU的核数决定 ,但 SocketConnector * 的线程 数量只有一 个, 也就 是 接收 客户端 连 接的线程 数只有 一个, * SocketConnector 的线程 数量不能 配 置。 **/ SocketConnector connector = new new new new SocketConnector(Run time. getRuntime() .availableProcessors() + 1, Executors.new Cac hedThreadPool ()); //从1--N 开始尝 试, N的最大 数量为 CPU核数 +1 SocketAcceptor acceptor = new SocketAcceptor(N, Executors.newCachedThreadPool()); 深入理解 Apache Mina ---- Mina 的ByteBuffer Author:中國壹石頭 ---------------------------------------------------------------------------------------------------------------------- What we call human nature is actually human habbit . 个IoFilter 添加到 IoFilterChain 中, 它的 作用 就是将 I/O Processor中的 事件 通过 其自身 封 装的 一个 线程 池来转 发到 下一个 过滤 器中 。在 没有添 加该 线程 模型时 , I/O Processor的事 件是 通过 方法 来触发 的, 然后 转发给 IoHandler。 在没有 添加 该线 程池的 时候 ,所 有的 事 件 都是 在单 线程 模式下 运行 的, 也 就 是说 有的事 件和 处理 (IO Processor,IoHandler,IoFilter) 都是 运行 在同 一个线 程上 ,这 个线程 就是 IO Processor的线 程, 但是 这个线 程的 数量 受到 CPU 核数 的 影响 ,因 此系 统的性 能也 直接受 CPU 核数 的影 响。 比较 复杂 的应 用一般 都会 用到 该线程 池, 你 可 以根 据你 的需 求在 IoFilterchain 中你 可以 添 加 任意 数量 的线 程池, 这些 线程 池可以 组合 成一个 事件 驱动 (SEDA)的处 理模 型。 对于一般 的 应用 来说 不是 线程的 数量 越多 越好, 线程 的数 量越多 可能 会加剧 CPU 切换 线程 所耗 费的时 间, 反而 会影 响系统 的性 能, 因此, 线程 的数 量需要 根据 实际 的需要 由小 到大 ,逐步 添加 , 知道 找到 适合 你系统 的最 佳线 程的数 量。 ExcutorFilter 的配 置过 程如 下: 在配 置该 线程 池的时 候需 要注 意的一个 问 题是 , 当 你 使用自 定的 ProtocolCodecFactory 时候 一定 要将 线程 池配置 在该 过滤 器之后 ,如 下所 示: 因为 你自 己实 现的 ProtocolCodecFactory 直接 读取 和转 换的是 二进 制数 据, 这 些 数据 都是 由 和CPU 绑定的 I/O Processor来读 取和 发送 的, 因 此 为 了不影 响系 统的 性能, 也 应 该将数 据 的编 解码 操作 绑定到 I/O Processor线 程中 , 因为 在 Java中创 建和 线程 切换都 是比 较耗 资 源 的, 因此 建议将 ProtocolCodecFactory 配置在 ExecutorFilter 的前 面。 关于 ProtocolCodecFactory详细 讲述 会在 后续的 文档 中给 出,此 处就 不多 说了。 最后 给出 一个 服务器 线程 模型 完整配 置的 例子 , 该例 子和 KFCClient 一起 配置 使用 , 详细 代 码在 附件 中, 此处只 给出 代码 的主要 部分 : SocketAcceptor acceptor = ...; DefaultIoFilterChainBuilder filterChainBuild er = acceptor.getDef aultConfig().getFilterChain(); filterChainBuild er.addLast("thr eadPool", new ExecutorFilter(Executors.n ewCachedThreadPool()); DefaultIoFilterChainBuilder filterChainBuild er = acceptor.getDef aultConfig().getFilterChain(); // 和CPU绑定的操 作配 置在过 滤 器的前 面 filterChainBuild er.addLast("codec", new ProtocolCodecFactory(...)); // 添加线程 池 filterChainBuild er.addLast("thr eadPool", new ExecutorFilter(Executors.n ewCachedThreadPool()); SocketAddress address = new new new new InetSocketAddress( "localhost" , 4321); /*** * 配置 SocketAcceptor 监听器的 I/O Processor 的线程的数 量 , 此处的 I/O * Processor 的线程 数量由 CPU的核数决定 ,但 Acceptor 的线程 数量只有 一个 ,也 就 是接收 客户端 连接的线 程 数只有一 个, * Acceptor 的线程 数量不能 配 置。 **/ IoAcceptor acceptor = new new new new SocketAcceptor(Run time. getRuntime () .availableProcessors() + 1, Executors.new Cac hedThreadPool ()); acceptor.getDef aultConfig().setThreadModel(ThreadModel. MANUAL); // 配置数 据的编解 码 器 acceptor.getDef aultConfig().getFilterChain().addLast( "codec", new new new new ProtocolCodecFilter( new new new new ObjectSerializationCodecFactory())); 深入理解 Apache Mina ---- Mina 的ByteBuffer Author:中國壹石頭 ---------------------------------------------------------------------------------------------------------------------- What we call human nature is actually human habbit . // 此处为 你自己实 现的编 解 码 器 // config .getFilterChain().addLast(" codec ", new // ProtocolCodecFactory(...)); // 为IoFilterChain 添加线程 池 acceptor.getDef aultConfig().getFilterChain().addLast( "threadPool", new new new new ExecutorFilter(Executors. new Cac hedThread Pool ())); acceptor.getDef aultConfig().getFilterChain().addLast( "logger", new new new new LoggingFilter()); // 绑定服 务器 端口 acceptor.bind(address, new new new new KFCFoodPriceHandler()); System. out.println(" 服务器 开始在 8000 端口监听 ......." ); // ==========================================// // 此处为 客户端的 I/O Processor 线程数的配 置,你 可以模 仿 // // IoAcceptor 配置来实 现 // // ==========================================// /*** * 配置 SocketConnector 监听器的 I/O Processor 的线程的数 量 , 此处的 I/O * Processor 的线程 数量由 CPU的核数决定 ,但 SocketConnector * 的线程数量只有一个,也就是接收客户端连接的线程数只有一个, SocketConnector 的线程 数量不能 配 置。 **/ // SocketConnector connector = new SocketConnector(Run time.g etRun time() //.availableProcessors() + 1, Executors.newCachedThreadPool()); }
还剩3页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 6 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf