mina2线程详解
1主要流程

read in data:
IO读入(IoProcessor)---日志记录、解码、threadPool(IoFilter)---业务逻辑处理(IoHandler)
write out data:
业务逻辑处理(IoHandler)---日志记录、编码、threadPool(IoFilter)---IO写出(IoProcessor)
由以上可以看出,IO读入和IO写出的过程是相反的。
2线程
这里主要讨论一下Mina中的线程,使用线程,线程池可以提高性能,Mina中就使用了几种线程:
- IoAcceptor/IoConnector线程
- IoProcessor线程
- IoHandler线程
2.1IoAcceptor/IoConnector线程
IoAcceptor用于监听客户端的连接,每监听一个端口建立一个线程。IoConnector用于与服务端建立连接,每连接一个服务端就建立一个线程。这两种线程都是通过线程池建立的,我们可以在构建对象的时候就指定线程池类型:
- public NioSocketAcceptor(Executor executor, IoProcessor<NioSession> processor) {}
- public NioSocketConnector(Executor executor, IoProcessor<NioSession> processor) {}
此类线程池的构造在源代码中为(AbstractIoService第168行):
- protected AbstractIoService(IoSessionConfig sessionConfig, Executor executor) {
- //省略部分代码
- if (executor == null) {
- this.executor = Executors.newCachedThreadPool();
- createdExecutor = true;
- } else {
- this.executor = executor;
- createdExecutor = false;
- }
- }
由此可见默认的线程池类型为newCachedThreadPool,这是一个可根据需要创建新线程的线程池,在以前构造的线程可用时可以重用它们。
2.2IoProcessor线程
对于一个IoAcceptor或IoConnector线程对应一个IoProcessor线程用于IO的处理,这个IoProcessor线程从IoProcessor线程池中取出。IoProcessor线程池的大小默认为机器的CPU核数+1,例如双核机器的IoProcessor的线程池大小默认为3,我们可以更改线程池的大小:
- IoConnector connector = new NioSocketConnector(9);
- IoAcceptor acceptor = new NioSocketAcceptor(9);
如上就把IoProcessor线程池的大小改为9个。
IoProcessor线程池的默认大小在源代码中的定义(SimpleIoProcessorPool第82行):
- private static final int DEFAULT_SIZE = Runtime.getRuntime().availableProcessors() + 1;
IoProcessor线程池的构造在源代码中为(SimpleIoProcessorPool第144行):
- public SimpleIoProcessorPool(Class<? extends IoProcessor<S>> processorType,
- Executor executor, int size) {
- //省略部分代码
- if (createdExecutor) {
- this.executor = Executors.newCachedThreadPool();
- } else {
- this.executor = executor;
- }
- }
2.3IoHandler线程
当我们在过滤器链中没有添加“threadPool”过滤器,则业务逻辑处理和IoProcessor使用同一个线程。如果设置了“threadPool”过滤器,则使用设置的线程池产生线程进行业务逻辑处理,过滤器的配置如下:
- acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));
如上配置之后,IO处理和业务逻辑处理将会使用各自的线程池产生线程使用。如果你的应用每次处理请求的时间较长而又希望应用能够有较好的响应性,那么最好是把处理业务逻辑的任务放到一个新的线程中去执行,而不是在 mina 框架创建的线程中去执行。
2.4各种线程的产生
- 当 IoAcceptor/IoConnector实例创建的时候,同时一个关联在IoAcceptor/IoConnector上的IoProcessor线程池也被创建。
- 当IoAcceptor/IoConnector建立套接字(IoAcceptor 的bind()或者是IoConnector 的connect()方法被调用)时,从线程池中取出一个线程,监听套接字端口。
- 当 IoAcceptor/IoConnector监听到套接字上有连接请求时,建立IoSession 对象,从IoProcessor池中取出一个IoProcessor线程执行IO处理。
- 如若过滤器中配置了“threadPool”过滤器,则使用此线程池建立线程执行业务逻辑(IoHandler)处理,否则使用IoProcessor线程处理业务逻辑。
3线程查看
举个例子通过jdk自带工具jvisualvm来查看线程:
- public class MinaTest {
- protected static Logger logger = LoggerFactory.getLogger(MinaTest.class);
- private static int PORT = 9999;
- public static void main(String[] args) {
- try {
- // 创建一个非阻塞的server端的Socket
- IoAcceptor acceptor = new NioSocketAcceptor();
- // 设置过滤器
- acceptor.getFilterChain().addLast("logger", new LoggingFilter());
- acceptor.getFilterChain().addLast("codec",
- new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
- acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));
- // 设置读取数据的缓冲区大小
- acceptor.getSessionConfig().setReadBufferSize(2048);
- // 读写通道10秒内无操作进入空闲状态
- acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
- // 绑定逻辑处理器
- acceptor.setHandler(new MinaServerHandler());
- // 绑定端口
- acceptor.bind(new InetSocketAddress(PORT));
- logger.info("服务端启动成功... 端口号为:" + PORT);
- } catch (Exception e) {
- logger.error("服务端启动异常....", e);
- e.printStackTrace();
- }
- }
- }
- public class MinaServerHandler extends IoHandlerAdapter {
- protected static Logger logger = LoggerFactory.getLogger(MinaServerHandler.class);
- public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
- logger.error("服务端发送异常...", cause);
- }
- public void messageReceived(IoSession session, Object message) throws Exception {
- String msg = message.toString();
- //如果是quit就关闭session退出
- if ("quit".equals(msg)) {
- session.close();
- }
- Date date = new Date();
- session.write(date.toString());
- }
- public void sessionCreated(IoSession session) throws Exception {
- logger.info("服务端与客户端创建连接...");
- }
- }
- 运行MinaTest类,启动服务器端。
- 开始->运行->cmd进入控制台 窗口。
- 输入:telnet 127.0.0.1 9999
- 再重复2、3步骤2次。
- 对jvisualvm的线程视图截图如下:

- 通过以上步骤我们可以看出我们打开了一个服务器端口,并用3个客户端进行连接,下面我们通过以上总结的知识来分析一下服务端产生的线程:
- NioSccketAcceptor为服务器端监听端口9999通过线程池创建的一个线程。
- NioProcessor-1、NioProcessor-2、NioProcessor-3为IoProcessor线程池创建的线程,用来IO处理。
- pool-3-thread-1、pool-3-thread-2、pool-3-thread-3为过滤器配置的线程池创建的线程,用来业务逻辑处理
mina2线程详解的更多相关文章
- 通用线程:POSIX 线程详解,第 3 部分 条件互斥量(pthread_cond_t)
使用条件变量提高效率 本文是 POSIX 线程三部曲系列的最后一部分,Daniel 将详细讨论如何使用条件变量.条件变量是 POSIX 线程结构,可以让您在遇到某些条件时“唤醒”线程.可以将它们看作是 ...
- “全栈2019”Java多线程第二十五章:生产者与消费者线程详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- python线程详解
#线程状态 #线程同步(锁)#多线程的优势在于可以同时运行多个任务,至少感觉起来是这样,但是当线程需要共享数据时,可能存在数据不同步的问题. #threading模块#常用方法:'''threadin ...
- 通用线程:POSIX 线程详解,第 3 部分
通用线程:POSIX 线程详解,第 3 部分 使用条件变量提高效率 Daniel Robbins, 总裁兼 CEO, Gentoo Technologies, Inc. 简介: 本文是 POSIX 线 ...
- POSIX 线程详解(经典必看)
http://www.cnblogs.com/sunminmin/p/4479952.html 总共三部分: 第一部分:POSIX 线程详解 ...
- mysql后台线程详解
1.mysql后台线程 mysql后台线程主要用于维持服务器的正常运行和完成用户提交的任务,主要包括:master thread,read thread,write thread,redo log t ...
- Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量
Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程: 1.线程是一堆指令,是操作系统调度 ...
- KafkaProducer Sender 线程详解(含详细的执行流程图)
目录 1.Sender 线程详解 2.RecordAccumulator 核心方法详解 温馨提示:本文基于 Kafka 2.2.1 版本. 上文 <源码分析 Kafka 消息发送流程> 已 ...
- std::thread线程详解(1)
目录 目录 简介 线程的使用 线程的创建 线程的方法和属性 std::jthread (C++20) stop_token (C++20) 总结 Ref 简介 本文主要介绍了标准库中的线程部分.线程是 ...
随机推荐
- MySQL 升级详细步骤 (包括 Percona)
MySQL 升级步骤 MySQL 5.1.72 升级到 MySQL 5.5.36 鉴于我在升级的时候遇到的麻烦问题,我觉得有必要把一些细节说清楚,免得引起误解了.感觉官方文档上的升级步骤写的比较简单, ...
- input只读属性区别
readonly disabled 相同点:都是禁止输入 不同点:readonly属性会把该input提交到form表单 disabled属性不会把该input提交到form表单
- tomcat 运行程序很慢 运行一段时间就报错: java.lang.OutOfMemoryError: PermGen space
java.lang.OutOfMemoryError: PermGen space 全称是Permanent Generation space,是指内存的永久保存区域. 由于这块内存主要是被JVM存放 ...
- 蛙蛙推荐:AngularJS学习笔记
为了降低前端代码的数量,提高可维护性,可测试性,学习了下AngularJS,正在准备投入项目开发中. AngularJS的概念比较多,如果面向对象方面的书理解的不透的话学习起来有些费劲,它的官方有个快 ...
- SQL入门经典(五) 之键和约束
这一篇博客主要讲键的创建,约束的创建.修改对象和删除对象. 主键:主键是每行的唯一标识符,必须包含唯一值(因此不能为NULL).由于主键在关系中数据库的重要性,因此它是所有键和约束中最重要的.一个表最 ...
- 使用WPF动态生成Code 39条形码
最近在看些条形码方面相关的资料,而如果只是看的话,效果似乎并不怎么好,所以决定动手做点Demo,以增强对相关知识的记忆. 这里是一个我编写的使用WPF生成Code 39的例子,Code 39的编码很简 ...
- Linux-磁盘管理小结
这篇博文主要总结了Linux磁盘的一些操作,主要是硬盘的加载,分区(MBR分区和GPT分区),分区的挂载,以及swap分区的加载设置. 基础命令 df查看磁盘分区使用状况 -l //仅显示本地磁盘(默 ...
- redis中使用redis-dump导出、导入、还原数据实例
转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/109.html?1455861283 redis的备份和还原,借助了第三方 ...
- 我心中的核心组件(可插拔的AOP)~第六回 消息组件~续
回到目录 上一回写消息组件已经是很久之前的事了,这一次准备把消息组件后续的东西说一下,事实上,第一篇文章主要讲的是发消息,而这一讲最要讲的是收消息,简单的说,就是消息到了服务器之后,如何从服务器实时的 ...
- Atitti 知识图谱构建方法attilax 总结
Atitti 知识图谱构建方法attilax 总结 1.1. 知识图谱schema构建(体系化)1 1.2. 纵向垂直拓展(向上抽象,向下属性拓展)2 1.3. 横向拓展2 1.4. 网拓展2 1 ...