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用于与服务端建立连接,每连接一个服务端就建立一个线程。这两种线程都是通过线程池建立的,我们可以在构建对象的时候就指定线程池类型:

  1. public NioSocketAcceptor(Executor executor, IoProcessor<NioSession> processor) {}
  2. public NioSocketConnector(Executor executor, IoProcessor<NioSession> processor) {}

此类线程池的构造在源代码中为(AbstractIoService第168行):

  1. protected AbstractIoService(IoSessionConfig sessionConfig, Executor executor) {
  2. //省略部分代码
  3. if (executor == null) {
  4. this.executor = Executors.newCachedThreadPool();
  5. createdExecutor = true;
  6. } else {
  7. this.executor = executor;
  8. createdExecutor = false;
  9. }
  10. }

由此可见默认的线程池类型为newCachedThreadPool,这是一个可根据需要创建新线程的线程池,在以前构造的线程可用时可以重用它们。

2.2IoProcessor线程 
对于一个IoAcceptor或IoConnector线程对应一个IoProcessor线程用于IO的处理,这个IoProcessor线程从IoProcessor线程池中取出。IoProcessor线程池的大小默认为机器的CPU核数+1,例如双核机器的IoProcessor的线程池大小默认为3,我们可以更改线程池的大小:

  1. IoConnector connector = new NioSocketConnector(9);
  2. IoAcceptor acceptor = new NioSocketAcceptor(9);

如上就把IoProcessor线程池的大小改为9个。 
IoProcessor线程池的默认大小在源代码中的定义(SimpleIoProcessorPool第82行):

  1. private static final int DEFAULT_SIZE = Runtime.getRuntime().availableProcessors() + 1;

IoProcessor线程池的构造在源代码中为(SimpleIoProcessorPool第144行):

  1. public SimpleIoProcessorPool(Class<? extends IoProcessor<S>> processorType,
  2. Executor executor, int size) {
  3. //省略部分代码
  4. if (createdExecutor) {
  5. this.executor = Executors.newCachedThreadPool();
  6. } else {
  7. this.executor = executor;
  8. }
  9. }

2.3IoHandler线程 
当我们在过滤器链中没有添加“threadPool”过滤器,则业务逻辑处理和IoProcessor使用同一个线程。如果设置了“threadPool”过滤器,则使用设置的线程池产生线程进行业务逻辑处理,过滤器的配置如下:

  1. 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来查看线程:

  1. public class MinaTest {
  2. protected static Logger logger = LoggerFactory.getLogger(MinaTest.class);
  3. private static int PORT = 9999;
  4. public static void main(String[] args) {
  5. try {
  6. // 创建一个非阻塞的server端的Socket
  7. IoAcceptor acceptor = new NioSocketAcceptor();
  8. // 设置过滤器
  9. acceptor.getFilterChain().addLast("logger", new LoggingFilter());
  10. acceptor.getFilterChain().addLast("codec",
  11. new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
  12. acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));
  13. // 设置读取数据的缓冲区大小
  14. acceptor.getSessionConfig().setReadBufferSize(2048);
  15. // 读写通道10秒内无操作进入空闲状态
  16. acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
  17. // 绑定逻辑处理器
  18. acceptor.setHandler(new MinaServerHandler());
  19. // 绑定端口
  20. acceptor.bind(new InetSocketAddress(PORT));
  21. logger.info("服务端启动成功... 端口号为:" + PORT);
  22. } catch (Exception e) {
  23. logger.error("服务端启动异常....", e);
  24. e.printStackTrace();
  25. }
  26. }
  27. }
  1. public class MinaServerHandler extends IoHandlerAdapter {
  2. protected static Logger logger = LoggerFactory.getLogger(MinaServerHandler.class);
  3. public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
  4. logger.error("服务端发送异常...", cause);
  5. }
  6. public void messageReceived(IoSession session, Object message) throws Exception {
  7. String msg = message.toString();
  8. //如果是quit就关闭session退出
  9. if ("quit".equals(msg)) {
  10. session.close();
  11. }
  12. Date date = new Date();
  13. session.write(date.toString());
  14. }
  15. public void sessionCreated(IoSession session) throws Exception {
  16. logger.info("服务端与客户端创建连接...");
  17. }
  18. }
  • 运行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线程详解的更多相关文章

  1. 通用线程:POSIX 线程详解,第 3 部分 条件互斥量(pthread_cond_t)

    使用条件变量提高效率 本文是 POSIX 线程三部曲系列的最后一部分,Daniel 将详细讨论如何使用条件变量.条件变量是 POSIX 线程结构,可以让您在遇到某些条件时“唤醒”线程.可以将它们看作是 ...

  2. “全栈2019”Java多线程第二十五章:生产者与消费者线程详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  3. python线程详解

    #线程状态 #线程同步(锁)#多线程的优势在于可以同时运行多个任务,至少感觉起来是这样,但是当线程需要共享数据时,可能存在数据不同步的问题. #threading模块#常用方法:'''threadin ...

  4. 通用线程:POSIX 线程详解,第 3 部分

    通用线程:POSIX 线程详解,第 3 部分 使用条件变量提高效率 Daniel Robbins, 总裁兼 CEO, Gentoo Technologies, Inc. 简介: 本文是 POSIX 线 ...

  5. POSIX 线程详解(经典必看)

    http://www.cnblogs.com/sunminmin/p/4479952.html 总共三部分: 第一部分:POSIX 线程详解                               ...

  6. mysql后台线程详解

    1.mysql后台线程 mysql后台线程主要用于维持服务器的正常运行和完成用户提交的任务,主要包括:master thread,read thread,write thread,redo log t ...

  7. Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量

    Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程:    1.线程是一堆指令,是操作系统调度 ...

  8. KafkaProducer Sender 线程详解(含详细的执行流程图)

    目录 1.Sender 线程详解 2.RecordAccumulator 核心方法详解 温馨提示:本文基于 Kafka 2.2.1 版本. 上文 <源码分析 Kafka 消息发送流程> 已 ...

  9. std::thread线程详解(1)

    目录 目录 简介 线程的使用 线程的创建 线程的方法和属性 std::jthread (C++20) stop_token (C++20) 总结 Ref 简介 本文主要介绍了标准库中的线程部分.线程是 ...

随机推荐

  1. 《利用Python进行数据分析》第4章学习笔记

    NumPy基础:数组和矢量计算 NumPy的ndarray:一种多维数组对象 该对象是一个快速灵活的大数据集容器.你可以利用这种数组对整块数据执行一些数学运算,其语法跟标量元素之间的运算一样 列表转换 ...

  2. 关于FluentNhibernate数据库连接配置,请教

      在用FluentNHibernate映射数据库,出现这个问题,一天多了也没解决,求各位大神支招 问题是与map对应的表已成功创建,出错的地方是最后的 .BuildSessionFactory(); ...

  3. 手机浏览器,微信中播放amr录音

    由于微信公众号开发中,临时素材只有三天的有效期,但是客户要求所有录音永久保存,永久素材数量又有限制,故只能把录音保存到服务器上.但是存到服务器上有一个问题,手机微信中无法直接播放amr录音.无意中发现 ...

  4. Java多线程20:多线程下的其他组件之CountDownLatch、Semaphore、Exchanger

    前言 在多线程环境下,JDK给开发者提供了许多的组件供用户使用(主要在java.util.concurrent下),使得用户不需要再去关心在具体场景下要如何写出同时兼顾线程安全性与高效率的代码.之前讲 ...

  5. 冲刺阶段 day 14

    项目进展 经过这几个星期的努力,我们已经完成了我们的软件工程项目,经过多次测试,项目已经可以准确无误地运行. 存在问题 测试期间,未发现问题. 心得体会 在这几个星期的努力下,我们终于完成了我们预期的 ...

  6. [.net 面向对象程序设计进阶] (8) 托管与非托管

    本节导读:虽然在.NET编程过程中,绝大多数内存垃圾回收由CLR(公共语言运行时)自动回收,但也有很多需要我们编码回收.掌握托管与非托管的基本知识,可以有效避免某些情况下导致的程序异常. 1.什么是托 ...

  7. MongoDB官网驱动仓库封装

    定义IMongoRepositoryBase接口 public interface IMongoRepositoryBase     {         /// <summary>     ...

  8. [ZigBee] 1、 ZigBee简介

    前言 目前,中国大力推广的物联网是zigbee 应用的主战场,物联网通过智能感知.识别技术与普适计算(我还特意申请了个域名psjs.vip).泛在网络的融合应用,被称为继计算机.互联网之后世界信息产业 ...

  9. salesforce 零基础开发入门学习(六)简单的数据增删改查页面的构建

    VisualForce封装了很多的标签用来进行页面设计,本篇主要讲述简单的页面增删改查.使用的内容和设计到前台页面使用的标签相对简单,如果需要深入了解VF相关知识以及标签, 可以通过以下链接查看或下载 ...

  10. SQLServer数据库备份

    使用sql语句备份数据: BACKUP DATABASE 数据库名称 TO DISK = '存储备份文件的路径\备份名称.bak' WITH INIT 使用例子: BACKUP DATABASE Sh ...