关于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()));
用什么线程池 自己实际考虑
关于mina内部有向个线程在执行---mina源代码分析相关推荐
- 【Java 并发编程】线程池机制 ( 线程池执行任务细节分析 | 线程池执行 execute 源码分析 | 先创建核心线程 | 再放入阻塞队列 | 最后创建非核心线程 )
文章目录 一.线程池执行任务细节分析 二.线程池执行 execute 源码分析 一.线程池执行任务细节分析 线程池执行细节分析 : 核心线程数 101010 , 最大小成熟 202020 , 非核心线 ...
- Android应用程序内部启动Activity过程(startActivity)的源代码分析
上文介绍了Android应用程序的启动过程,即应用程序默认Activity的启动过程,一般来说,这种默认Activity是在新的进程和任务中启动的:本文将继续分析在应用程序内部启动非默认Activit ...
- Java:使用匿名内部类在方法内部定义并启动线程
下面的代码展示了在一个方法中,通过匿名内部类定义一个Thread,并Override它的run()方法,之后直接启动该线程. 这样的代码可用于在一个类内部通过另起线程来执行一个支线任务,一般这样的任务 ...
- Java 使用匿名内部类在方法内部定义并启动线程
下面的代码展示了在一个方法中,通过匿名内部类定义一个Thread,并Override它的run()方法,之后直接启动该线程. 这样的代码可用于在一个类内部通过另起线程来执行一个支线任务,一般这样的任务 ...
- 从原理到实现丨手把手教你写一个线程池丨源码分析丨线程池内部组成及优化
人人都能学会的线程池 手写完整版 1. 线程池的使用场景 2. 线程池的内部组成 3. 线程池优化 [项目实战]从原理到实现丨手把手教你写一个线程池丨源码分析丨线程池内部组成及优化 内容包括:C/C+ ...
- 阿里内部禁用Executors创建线程池,为什么?
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 何甜甜在吗 来源 | http://rrd.m ...
- Java并发编程实战(chapter_3)(线程池ThreadPoolExecutor源码分析)
为什么80%的码农都做不了架构师?>>> 这个系列一直没再写,很多原因,中间经历了换工作,熟悉项目,熟悉新团队等等一系列的事情.并发课题对于Java来说是一个又重要又难的一大块 ...
- Java 线程池框架核心代码分析--转
原文地址:http://www.codeceo.com/article/java-thread-pool-kernal.html 前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和 ...
- Java线程池框架核心代码分析
前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和资源消耗都是很高的.线程池应运而生,成为我们管理线程的利器.Java 通过Executor接口,提供了一种标准的方法将任务的提交过 ...
最新文章
- 肤色检测算法 - 基于不同颜色空间简单区域划分的皮肤检测算法
- Nimbus/Supervisor本地目录结构
- 在SCSS文件中导入常规CSS文件?
- 基于SSVEP-EOG的混合BCI用于机械臂控制
- copying mysql status_mysql慢查询copying to tmp table
- inux CentOS 7 修改内核启动默认顺序
- Java标识符和关键字(static,final,abstract,interface)
- 工具的使用——vs2013(二)
- greenplum管理员日常任务
- 剑指offer、二叉搜索树的第K个结点(python)
- q 与 blockquote 的区别
- 端口和波特率测试软件,端口和波特率检测工具
- opera Reservation More Fields(接送机)
- 解决sockscap64测试代理可以,实际应用无法联网的问题
- Linux内核专题 - 介绍
- c语言 格式化硬盘,在Windows 7上用c ++格式化硬盘(Formatting a hard disk in c++ on Windows 7)...
- 【嵌入式13】两台电脑串口通信
- 项目实战4——uniapp在线升级关联云空间
- 今天一个大龄同事被辞退了,顿时让我思绪万千。程序员32岁是一个坎,大龄程序员的出路到底在哪?
- Windows系统上的软件(如:爱奇艺万能播放器)固定任务栏图标后,打开后出现新任务栏图标
热门文章
- qt 3d迷宫游戏_玩迷宫也能解锁孩子空间思维,各年龄必备迷宫书单推荐(附游戏资源下载)...
- 盲盒包装流水线 (25 分) C语言
- BUUCTF | Misc 二维码 -- BUUOJ WriteUP
- 第五十五讲 插件设备树
- 【服务器管理】mount.nfs: Stale file handle的解决办法
- 多人使用服务器,如何开个人账户?以及 个人账户如何操作服务器?
- ZT210打印标签方法及常见问题20230110
- 301重定向解决域名被墙教程
- 开源团队聊天工具——RocketChat的介绍及部署
- 对YY/T 0287-2017 医疗器械 质量管理体系的一些学习