关于mina内部有向个线程在执行---mina源代码分析

最近,看了一个大牛写的mina源代码分析,转一下,http://www.zoomhoo.com/viewthread.jsp?tid=261&am

apache MINA 源码级分析

如果对MINA不了解请看
http://www.ibm.com/developerworks/cn/opensource/os-cn-apmina/
关键字: mina 线程
最近,项目结束[项目主要是大量文件处理,所以自己用jdk5与spring做了很多线程池异步协作处理],
闲暇回顾哈NIO学习哈MINA;

首先我们需要了解MINA是什么?

我们首先需要明确第一步;一个网络通信到底可以抽象为几步;

方式一:从请求道响应看成一个流水线[呵呵想想福特汽车的流水线]
方式二:服务器接收客户请求,剩下处理[两个车间了哦]
方式三:服务器接收请求,读取客户信息,处理业务[三个车间了]

传统的:tomcat等服务器怎么处理的,简单看做方式二,一般开多线程[线程池]作为第二个车间
问题,线程多了上下文切换等问题,这个网络很多说这个问题的
现在的:grizzly,mina,netty等看做第三种,但是每个车间的写作才是关键,第二个车间 可以注册在第一个车间当来料处理第一个车间自动找到第二个,还有就是第二个车间可以通过回调函数

那看看MINA的结构[图片来源互联网]



从上图我们可以把MINA分作三个车间
1 车间 IoService----主要任务接受客户请求构造session[客户所有信息以及mina上下文信息],调用[异步]2车间处理
2 车间 IoProcessor[IoFilter包括在此车间]--主要任务IO处理意见filter执行然后 同步或者异步执行 3车间
3 车间 IoHandler--主要是我们的业务处理[mina使我们不关心网络,IO只关心这里]

但是实际情况望望比想象的复杂,如果MINA拿过来就用你很可能发现不是那样效率
特别是你的3车间 处理的连接数据库 或者链接其他网络信息,你的服务器编程blocking了

为什么?
请看下篇:




我们首先看一个MINA最简单的服务器代码 如下
Java代码 

package org.apache.mina.example.echoserver;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.example.echoserver.ssl.BogusSslContextFactory;
import org.apache.mina.filter.ssl.SslFilter;
import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

public 
class Main {
public 
static 
void main(String[] args) throws Exception {
SocketAcceptor acceptor = new NioSocketAcceptor();
acceptor.setReuseAddress(true);
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();

chain.addLast("logger", new LoggingFilter());

package org.apache.mina.example.echoserver;import java.net.InetSocketAddress;import java.util.concurrent.Executors;import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;import org.apache.mina.example.echoserver.ssl.BogusSslContextFactory;import org.apache.mina.filter.ssl.SslFilter;import org.apache.mina.filter.executor.ExecutorFilter;import org.apache.mina.filter.logging.LoggingFilter;import org.apache.mina.transport.socket.SocketAcceptor;import org.apache.mina.transport.socket.nio.NioSocketAcceptor;public class Main { public static void main(String[] args) throws Exception { SocketAcceptor acceptor = new NioSocketAcceptor(); acceptor.setReuseAddress(true); DefaultIoFilterChainBuilder chain = acceptor.getFilterChain(); chain.addLast("logger", new LoggingFilter());Java代码 


//这里是演示所以是单线程,实际是new ProtocolCodecFilter(new ImageCodecFactory(false)) 
// chain.addLast("threadPool", new ExecutorFilter(Executors.newSingleThreadExecutor())); 
// Bind 
acceptor.setHandler(new EchoProtocolHandler());
acceptor.bind(new InetSocketAddress(8080));
System.out.println("Listening on port " + 8080);


}

//这里是演示所以是单线程,实际是new ProtocolCodecFilter(new ImageCodecFactory(false)) // chain.addLast("threadPool", new ExecutorFilter(Executors.newSingleThreadExecutor())); // Bind acceptor.setHandler(new EchoProtocolHandler()); acceptor.bind(new InetSocketAddress(8080)); System.out.println("Listening on port " + 8080); } 
我们执行这段代码,然后用telnet连接看看 情况如何? 

org.apache.mina.example.echoserver.Main 
size is 3 
[15:26:38] INFO [org.apache.mina.transport.socket.nio.NioSocketAcceptor] - init prepare Selector.open() Thread info--> main 
Listening on port 8080 
[15:26:41] INFO[org.apache.mina.transport.socket.nio.NioSocketAcceptor] - accept anclient connection thread info-->NioSocketAcceptor-1 
[15:26:41]INFO [org.apache.mina.filter.logging.LoggingFilter] - OPENEDThreadinfo--> NioProcessor-1 nextFilter is classorg.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1 
[15:26:41] INFO [org.apache.mina.example.echoserver.EchoProtocolHandler] - OPENED Thread info--> NioProcessor-1 
[15:26:43]INFO [org.apache.mina.transport.socket.nio.NioSocketAcceptor] - acceptan client connection thread info-->NioSocketAcceptor-1 
[15:26:43]INFO [org.apache.mina.filter.logging.LoggingFilter] - OPENEDThreadinfo--> NioProcessor-2 nextFilter is classorg.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1 
[15:26:43] INFO [org.apache.mina.example.echoserver.EchoProtocolHandler] - OPENED Thread info--> NioProcessor-2 
[15:26:45]INFO [org.apache.mina.transport.socket.nio.NioSocketAcceptor] - acceptan client connection thread info-->NioSocketAcceptor-1 
[15:26:45]INFO [org.apache.mina.filter.logging.LoggingFilter] - OPENEDThreadinfo--> NioProcessor-3 nextFilter is classorg.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1 
[15:26:45] INFO [org.apache.mina.example.echoserver.EchoProtocolHandler] - OPENED Thread info--> NioProcessor-3 
[15:26:50]INFO [org.apache.mina.transport.socket.nio.NioSocketAcceptor] - acceptan client connection thread info-->NioSocketAcceptor-1 
[15:27:01] INFO [org.apache.mina.example.echoserver.EchoProtocolHandler] - --sleeping wake up 20 seconds--- 
[15:27:01]INFO [org.apache.mina.filter.logging.LoggingFilter] - OPENEDThreadinfo--> NioProcessor-1 nextFilter is classorg.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1 
[15:27:01] INFO [org.apache.mina.example.echoserver.EchoProtocolHandler] - OPENED Thread info--> NioProcessor-1 
[15:27:03] INFO [org.apache.mina.example.echoserver.EchoProtocolHandler] - --sleeping wake up 20 seconds--- 
[15:27:05] INFO [org.apache.mina.example.echoserver.EchoProtocolHandler] - --sleeping wake up 20 seconds--- 


以上是执行的日志信息[本人在源代码增加了日志,mina的日志真是差啊]

下面我们分析哈日志看看问题:
首先我们看到2中类型的线程池
一:NioSocketAcceptor
二:NioProcessor
每次客户端连接 服务器都是NioSocketAcceptor接受请求转给NioProcessor
第一次连接NioProcessor-1 执行LoggingFilter在执行EchoProtocolHandler[这里线程我让他sleep 20秒]
第二次连接NioProcessor-2 执行LoggingFilter在执行EchoProtocolHandler[这里线程我让他sleep 20秒]
第三次连接NioProcessor-3 执行LoggingFilter在执行EchoProtocolHandler[这里线程我让他sleep 20秒]
第四次连接NioSocketAcceptor accept以后转交给NioProcessor但是NioProcessor线程池线程用完,只能阻塞[线程池大小是3,为什么是3,下面看代码] 第一个线程执行完毕 来处理第四个请求

这样我们明白 我们的 业务处理实现IOHandler的类和IoProcessor用一个线程,这样一旦我们的处理类阻塞则服务器就停滞了;

这样:就是我第一步内容说的 相当于只有2个车间,我们需要把 2车间拆分为 2个车间异步[流水]作业

具体拆分 上面看代码,打开 注释就ok了

我们简单看看源代码:

我们首先
SocketAcceptor acceptor = new NioSocketAcceptor();

那么到底做了什么我们看看NioSocketAcceptor构造器吧

public NioSocketAcceptor() {
super(new DefaultSocketSessionConfig(), NioProcessor.class);
((DefaultSocketSessionConfig) getSessionConfig()).init(this);
}

我们在看看super(new DefaultSocketSessionConfig(), NioProcessor.class);
这个代码

protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,
Class<? extends IoProcessor<T>> processorClass) {
this(sessionConfig, null, new SimpleIoProcessorPool<T>(processorClass),
true);
}

看看上面蓝色色代码,构造IoProcessorPool线程池了 那大小是几
看看构造器
public SimpleIoProcessorPool(Class<? extends IoProcessor<T>> processorType) {
this(processorType, null, DEFAULT_SIZE);
System.out.println("size is "+DEFAULT_SIZE);
}
private static final int DEFAULT_SIZE = Runtime.getRuntime().availableProcessors() + 1;

明白了,就是cpu数+1 本机器是一个cpu双核的 所以是3

但是不要忘记 3要做的事情很多 项目希望把 业务处理的事情不让这个3做


通过分离业务与io处理的线程池 这样 业务的阻塞不会导致IO处理的阻塞

[16:24:14] INFO[org.apache.mina.transport.socket.nio.NioSocketAcceptor] - accept anclient connection thread info-->NioSocketAcceptor-1 [16:24:14] INFO[org.apache.mina.filter.logging.LoggingFilter] - OPENEDThreadinfo--> NioProcessor-1 nextFilter is classorg.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1[16:24:15] INFO[org.apache.mina.example.echoserver.EchoProtocolHandler] - OPENEDThread info--> pool-3-thread-1 [16:24:15] INFO[org.apache.mina.transport.socket.nio.NioSocketAcceptor] - accept anclient connection thread info-->NioSocketAcceptor-1 [16:24:15] INFO[org.apache.mina.filter.logging.LoggingFilter] - OPENEDThreadinfo--> NioProcessor-2 nextFilter is classorg.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1[16:24:16] INFO[org.apache.mina.transport.socket.nio.NioSocketAcceptor] - accept anclient connection thread info-->NioSocketAcceptor-1 [16:24:16] INFO[org.apache.mina.filter.logging.LoggingFilter] - OPENEDThreadinfo--> NioProcessor-3 nextFilter is classorg.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1[16:24:17] INFO[org.apache.mina.transport.socket.nio.NioSocketAcceptor] - accept anclient connection thread info-->NioSocketAcceptor-1 [16:24:17] INFO[org.apache.mina.filter.logging.LoggingFilter] - OPENEDThreadinfo--> NioProcessor-1 nextFilter is classorg.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1[16:24:35] INFO[org.apache.mina.example.echoserver.EchoProtocolHandler] - --sleepingwake up 20 seconds---

从日志可以看出 现在 accept ioprocess iohandler各自自己的线程池 这样才 真的异步

chain.addLast("threadPool", new ExecutorFilter(Executors.newSingleThreadExecutor()));

关键所在 不加则2,3车间公用一个线程池

实践不可能单线 一般
chain.addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));
用什么线程池 自己实际考虑

你可能感兴趣的:(apache,thread,多线程,socket,Mina)