一、三种工作线程:

(一) Acceptor  thread:

该线程的作用是接收客户端的连接,并将客户端的连接导入到IOProcessor线程模型中。Acceptor thread在调用了Acceptor.bind()方法后启动。IoAcceptor用于监听客户端的连接,每监听一个端口建立一个线程。每个Acceptor只能创建一个Acceptor thread,该线程模型不能配置(可以在Acceptor.bind时绑定多个端口,这样就能有多个Acceptor Thread,提高服务器对客户端连接的效率),它由Mina自身提供。

(二) Connector thread:

该线程模型是客户端的连接线程模型,它的作用和Acceptor thread类似,它将客户端与服务器的连接导入到IOProcessor线程模型中。IoConnector用于与服务端建立连接,每连接一个服务端就建立一个线程。同样地,该线程模型也是由Mina的客户端自动创建,该线程模型也不能进行配置。

(三) IOProcessor thread:

该线程模型的主要作用就是接收和发送数据,所有的IO操作在服务器与客户端的连接建立后,所有的数据的接收和发送都是有该线程模型来负责的,直到客户端与服务器的连接关闭,该线程模型才停止工作。该线程模型可以由程序员根据需要进行配置。该线程模型默认的线程的数量为cpu的核数+1。若你的cpu为双核的,则你的I/O processor线程的最大数量为3,同理若你的若你的cpu为四核的,那么你的I/O processor线程的最大数量为5。

由上面的内容我们可以知道在Mina中可以配置的线程数量只有IOProcessor,对于每个IoService在创建其实例的时候可以配置该IoService的IOProcessor的线程数量。在

SokcetConnector和SocketAccpetor中IOPProcessor的数量是由CPU的核数+1来决定的。

二、线程模型:

单一的Processor线程内部来看,IO请求的处理流程是单线程顺序处理的。当Process线程select了一批就绪的IO请求后,会在线程内部逐一对这些IO请求进行处理。处理的流程包括IoFilter和IoHandler里的逻辑。当前面的IO请求处理完毕后,才会取下一个IO请求进行处理。也就是说,如果IoFilter或IoHandler中有比较耗时的操作的话(如:读取数据库等),Processor线程将会被阻塞住,后续的请求将得不到处理。这样的情况在高并发的服务器下显然是不能容忍的。于是,Mina通过在处理流程中引入线程池来解决这个问题。

IoFilterChain是Mina的扩展点。Mina里是通过IoFilter的形式来为处理流程添加线程池的。Mina的线程模型主要有一下这几种形式:

1、单线程模型,也是Mina默认线程模型。也就是Processor包办了从底层IO到上层的IoHandler逻辑的所有执行工作。这种模型比较适合于处理逻辑简单,能快速返回的情况。

2、在IoFilterChain中加入了Thread Pool Filter。此时的处理流程变为Processor线程读取完数据后,执行IoFilterChain的逻辑。当执行到Thread Pool Filter的时候,该Filter会将后续的处理流程封装到一个Runnable对象中,并交由Filter自身的线程池来执行,而Processor线程则能立即返回来处理下一个IO请求。这样如果后面的IoFilter或IoHandler中有阻塞操作,只会引起Filter线程池里的线程阻塞,而不会阻塞住Processor线程,从而提高了服务器的处理能力。Mina提供了Thread Pool Filter的一个实现:ExecutorFilter。

3、没有限制说chain中只能添加一个ExecutorFilter,开发者也可以在chain中加入多个ExecutorFilter来构成第三种情况,但一般情况下可能没有这个必要。

三、ExecutorFilter:

添加ExecutorFilter到IOFilterChain中的代码如下:

 acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool())); 

ExecutorFilter创建时的主要参数有:

1、指定线程池的属性信息,譬如:核心大小、最大大小、等待队列的性质等。特别要关注的是ExecutorFilter 内部默认使用的是OrderedThreadPoolExecutor 作为线程池的实现,从名字上可以看出是保证各个事件在多线程执行中的顺序;

2、哪些事件方法被关注,也就哪些事件方法用这个线程池执行。线程池可以异步执行的事件类型是位于IoEventType 中的九个枚举值中除了SESSION_CREATED 之外的其余八个,这说明Session 建立的事件只能与IoProcessor 在同一个线程上执行。

默认情况下,没有配置关注的事件类型,有如下六个事件方法会被自动使用线程池异步执行:

IoEventType.EXCEPTION_CAUGHT,
IoEventType.MESSAGE_RECEIVED,
IoEventType.MESSAGE_SENT,
IoEventType.SESSION_CLOSED,
IoEventType.SESSION_IDLE,
IoEventType.SESSION_OPENED

3、绝对不能开启线程让其执行sessionCreated()方法。如果你真的打算使用这个ExecutorFilter,那么最好想清楚它该放在过滤器链的哪个位置,针对哪些事件做异步处理机制。一般ExecutorFilter 都是要放在ProtocolCodecFilter 过滤器的后面,也就是不要让编解码运行在独立的线程上,而是要运行在IoProcessor 所在的线程,因为编解码处理的数据都是由IoProcessor 读取和发送的,没必要开启新的线程,否则性能反而会下降。一般使用ExecutorFilter 的典型场景是将业务逻辑(譬如:耗时的数据库操作)放在单独的线程中运行,也就是说与IO 处理无关的操作可以考虑使用ExecutorFilter 来异步执行。

4、请求的处理顺序:

在处理流程中加入线程池,可以较好的提高服务器的吞吐量,但也带来了新的问题:请求的处理顺序问题。在单线程的模型下,可以保证IO请求是挨个顺序地处理的。加入线程池之后,同一个IoSession的多个IO请求可能被ExecutorFilter并行的处理,这对于一些对请求处理顺序有要求的程序来说是不希望看到的。比如:数据库服务器处理同一个会话里的prepare,execute,commit请求希望是能按顺序逐一执行的。

Mina里默认的实现是有保证同一个IoSession中IO请求的顺序的。具体的实现是,ExecutorFilter默认采用了Mina提供的OrderedThreadPoolExecutor作为内置线程池。后者并不会立即执行加入进来的Runnable对象,而是会先从Runnable对象里获取关联的IoSession(这里有个down cast成IoEvent的操作),并将Runnable对象加入到session的任务列表中。OrderedThreadPoolExecutor会按session里任务列表的顺序来处理请求,从而保证了请求的执行顺序。

对于没有顺序要请求的情况,可以为ExecutorFilter指定一个Executor来替换掉默认的OrderedThreadPoolExecutor,让同一个session的多个请求能被并行地处理,来进一步提高吞吐量。

5、ExecutorFilter 的工作机制很简单,就是在调用下一个过滤器的事件方法时,封装成IoFilterEvent对象并把其交给Executor 的execute(Runnable runnable)方法来执行:

 ………………
@Override
public final void messageReceived(NextFilter nextFilter, IoSession session, Object message) {
if (eventTypes.contains(IoEventType.MESSAGE_RECEIVED)) {
IoFilterEvent event = new IoFilterEvent(nextFilter, IoEventType.MESSAGE_RECEIVED, session, message);
fireEvent(event);
} else {
nextFilter.messageReceived(session, message);
}
}
@Override
public final void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) {
if (eventTypes.contains(IoEventType.MESSAGE_SENT)) {
IoFilterEvent event = new IoFilterEvent(nextFilter, IoEventType.MESSAGE_SENT, session, writeRequest);
fireEvent(event);
} else {
nextFilter.messageSent(session, writeRequest);
}
}
……………… protected void fireEvent(IoFilterEvent event) {
executor.execute(event);
}

四、各种线程的产生:

1、当 IoAcceptor/IoConnector实例创建的时候,同时一个关联在IoAcceptor/IoConnector上的IoProcessor线程池也被创建。

2、当IoAcceptor/IoConnector建立套接字(IoAcceptor 的bind()或者是IoConnector 的connect()方法被调用)时,从线程池中取出一个线程,监听套接字端口。

3、当 IoAcceptor/IoConnector监听到套接字上有连接请求时,建立IoSession 对象,从IoProcessor池中取出一个IoProcessor线程执行IO处理。

4、如若过滤器中配置了“threadPool”过滤器,则使用此线程池建立线程执行业务逻辑(IoHandler)处理,否则使用IoProcessor线程处理业务逻辑。

MINA线程模型的更多相关文章

  1. Mina、Netty、Twisted一起学(十):线程模型

    要想开发一个高性能的TCP服务器,熟悉所使用框架的线程模型非常重要.MINA.Netty.Twisted本身都是高性能的网络框架,如果再搭配上高效率的代码,才能实现一个高大上的服务器.但是如果不了解它 ...

  2. Mina的线程模型

    在Mina的NIO模式中有三种I/O工作线程(这三种线程模型只在NIOSocket中有效,在NIO数据包和虚拟管道中没有,也不需要配置): IoAcceptor/IoConnector线程 IoPro ...

  3. 【Netty源码分析】Reactor线程模型

    1. 背景 1.1. Java线程模型的演进 1.1.1. 单线程 时间回到十几年前,那时主流的CPU都还是单核(除了商用高性能的小机),CPU的核心频率是机器最重要的指标之一. 在Java领域当时比 ...

  4. Netty系列之Netty线程模型

    Reference: http://www.infoq.com/cn/articles/netty-threading-model 1. 背景 1.1. Java线程模型的演进 1.1.1. 单线程 ...

  5. 看我是如何处理自定义线程模型---java

    看过我之前文章的园友可能知道我是做游戏开发,我的很多思路和出发点是按照游戏思路来处理的,所以和web的话可能会有冲突,不相符合. 来说说为啥我要自定义线程模型呢? 按照我做的mmorpg或者mmoar ...

  6. HBase的Write Ahead Log (WAL) —— 整体架构、线程模型

    解决的问题 HBase的Write Ahead Log (WAL)提供了一种高并发.持久化的日志保存与回放机制.每一个业务数据的写入操作(PUT / DELETE)执行前,都会记账在WAL中. 如果出 ...

  7. Netty学习三:线程模型

    1 Proactor和Reactor Proactor和Reactor是两种经典的多路复用I/O模型,主要用于在高并发.高吞吐量的环境中进行I/O处理. I/O多路复用机制都依赖于一个事件分发器,事件 ...

  8. WPF QuickStart系列之线程模型(Thread Model)

    这篇博客将介绍WPF中的线程模型. 首先我们先来看一个例子,用来计算一定范围内的素数个数. XAML: <Grid> <Grid.RowDefinitions> <Row ...

  9. servlet的生命周期与运行时的线程模型

    第 14 章 生命周期 注意 讲一下servlet的生命周期与运行时的线程模型,对了解servlet的运行原理有所帮助,这样才能避免一些有冲突的设计. 如果你不满足以下任一条件,请继续阅读,否则请跳过 ...

随机推荐

  1. matlab运行中出现“Caught "std::exception" Exception message is: Message Catalog MATLAB:builtins was not loaded from the file."

    在我运行过程中,经常爆出这一不确定是什么的问题,经排查后发现,原来是fopen 文件后,没有及时fclose导致的.

  2. Gym - 100971J (思维+简单bfs)

    题目链接:http://codeforces.com/gym/100971/problem/J J. Robots at Warehouse time limit per test 2.0 s mem ...

  3. Alpha冲刺3

    前言 队名:拖鞋旅游队 组长博客:https://www.cnblogs.com/Sulumer/p/9971198.html 作业博客:https://edu.cnblogs.com/campus/ ...

  4. php优秀框架codeigniter学习系列——index.php

    程序流程图 先来看看CI框架运行的程序流程图. 从图中我们 看到,index.php作为唯一的入口文件,会初始化CI框架运行所需的基本资源. 路由器(Routing)会根据http请求,确定如何处理: ...

  5. HDU 6092 17多校5 Rikka with Subset(dp+思维)

    Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he ...

  6. HDU 6090 17多校5 Rikka with Graph(思维简单题)

    Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he ...

  7. HDU 6047 17多校 Maximum Sequence(优先队列)

    Problem Description Steph is extremely obsessed with “sequence problems” that are usually seen on ma ...

  8. 前端笔记 (3.JavaScript 2)

    一般来说,js代码越来越庞大的时候,最好要把它存在一个js文件中, 通过src引入即可,这样具有维护性高,可缓存(加载一次,无需加载) 方便未来拓展的特性 正确写法: <script type= ...

  9. Spring Boot 揭秘与实战(二) 数据存储篇 - MongoDB

    文章目录 1. 环境依赖 2. 数据源 2.1. 方案一 使用 Spring Boot 默认配置 2.2. 方案二 手动创建 3. 使用mongoTemplate操作4. 总结 3.1. 实体对象 3 ...

  10. [LeetCode&Python] Problem 830. Positions of Large Groups

    In a string S of lowercase letters, these letters form consecutive groups of the same character. For ...