【MINA】OrderedThreadPoolExecutor和UnorderedThreadPoolExecutor的事件监听线程池的选择
mina中有两个线程池概念 1.处理监听建立连接的线程池 2.处理读写事件的线程池
本文中主要探讨读写事件的线程池的选择
这两种都经过实际项目的使用和检测,说说优缺点
早期的项目是用UnorderedThreadPoolExecutor【无序线程池】
特点:线程池管理一个无界阻塞队列,线程在分配事件,并发处理maximumPoolSize个事件,
后面来的事件在没有空闲线程的时候要进入这个无界阻塞队列等待执行
可以看出,他的特点是session之间是没有影响的,从事件的执行效率上要更高一些,但是同session的事件执行顺序很难保证
UnorderedThreadPoolExecutor源码 public UnorderedThreadPoolExecutor(
int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
ThreadFactory threadFactory, IoEventQueueHandler queueHandler) { super(0, 1, keepAliveTime, unit, new LinkedBlockingQueue<Runnable>(), threadFactory, new AbortPolicy());
if (corePoolSize < 0) {
throw new IllegalArgumentException("corePoolSize: " + corePoolSize);
} if (maximumPoolSize == 0 || maximumPoolSize < corePoolSize) {
throw new IllegalArgumentException("maximumPoolSize: " + maximumPoolSize);
} if (queueHandler == null) {
queueHandler = IoEventQueueHandler.NOOP;
} this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.queueHandler = queueHandler;
} @Override
public void execute(Runnable task) {
if (shutdown) {
rejectTask(task);
} checkTaskType(task); IoEvent e = (IoEvent) task;
boolean offeredEvent = queueHandler.accept(this, e);
if (offeredEvent) {
getQueue().offer(e);
} addWorkerIfNecessary(); if (offeredEvent) {
queueHandler.offered(this, e);
}
}
后来的新项目使用了OrderedThreadPoolExecutor【有序的线程池】
特点:每个session有自己的事件队列,线程池在分配session,相当于每个session有唯一的线程在处理session中的任务队列,如果没有空闲线程可调度,
那么其他session就只能进入waitingSessions这个阻塞队列等待有空闲线程接管这个session的任务队列
可以看出,session之间是有影响的,但是保证了同session的事件执行是有序的
MyOrderedThreadPoolExecutor代码完全抄OrderedThreadPoolExecutor目地是想加入一个参数
maxQueueSize控制每个session任务队列的最大长度,超出就丢弃后进的任务
public MyOrderedThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit, ThreadFactory threadFactory,
IoEventQueueHandler eventQueueHandler, int maxQueueSize) {
// 从这里可以看到,其实现类似于{@link Executors.newCachedThreadPool},不过其可以设置corePoolSize和maximumPoolSize.
// 不过其execute方法是自实现的,否则如果用父类的则会出现问题,即在任务繁忙的时候会出现任务被拒绝
// 因为其把任务放到了session的任务队列中.即没有由线程池本身来保存
// 另外可以看到初始化的corePoolSize和maximumPoolSize分别传了0和1.这是为了更好的处理异常,因为super不能try/catch
super(DEFAULT_INITIAL_THREAD_POOL_SIZE, 1, keepAliveTime, unit,
new SynchronousQueue<Runnable>(), threadFactory,
new AbortPolicy()); if (corePoolSize < DEFAULT_INITIAL_THREAD_POOL_SIZE) {
throw new IllegalArgumentException("corePoolSize: " + corePoolSize);
} if ((maximumPoolSize == 0) || (maximumPoolSize < corePoolSize)) {
throw new IllegalArgumentException("maximumPoolSize: "
+ maximumPoolSize);
} // Now, we can setup the pool sizes
super.setCorePoolSize(corePoolSize);
super.setMaximumPoolSize(maximumPoolSize); // The queueHandler might be null.
if (eventQueueHandler == null) {
this.eventQueueHandler = IoEventQueueHandler.NOOP;
} else {
this.eventQueueHandler = eventQueueHandler;
} this.maxQueueSize = maxQueueSize;
} @Override
public void execute(Runnable task) {
if (shutdown) {
rejectTask(task);
} // Check that it's a IoEvent task
checkTaskType(task); IoEvent event = (IoEvent) task; // Get the associated session
IoSession session = event.getSession(); // Get the session's queue of events
SessionTasksQueue sessionTasksQueue = getSessionTasksQueue(session);
Queue<Runnable> tasksQueue = sessionTasksQueue.tasksQueue;
//超过任务队列上限就丢弃任务,目前定的值时20
if (tasksQueue.size() > this.maxQueueSize) {
LOGGER.error(com.youxigu.dynasty2.i18n.MarkupMessages.getString("MyOrderedThreadPoolExecutor_0"), session.getRemoteAddress(),
this.maxQueueSize);
rejectTask(task);
return;
}
boolean offerSession; // propose the new event to the event queue handler. If we
// use a throttle queue handler, the message may be rejected
// if the maximum size has been reached.
boolean offerEvent = eventQueueHandler.accept(this, event); if (offerEvent) {
// Ok, the message has been accepted
synchronized (tasksQueue) {
// Inject the event into the executor taskQueue
tasksQueue.offer(event); if (sessionTasksQueue.processingCompleted) {
sessionTasksQueue.processingCompleted = false;
offerSession = true;
} else {
offerSession = false;
} if (LOGGER.isDebugEnabled()) {
print(tasksQueue, event);
}
}
} else {
offerSession = false;
} if (offerSession) {
// As the tasksQueue was empty, the task has been executed
// immediately, so we can move the session to the queue
// of sessions waiting for completion.
waitingSessions.offer(session);
} addWorkerIfNecessary(); if (offerEvent) {
eventQueueHandler.offered(this, event);
}
}
1.为什么要选用后者那
在业务层通常是有locker控制并发,但是还是可能产生并发事件,导致数据错乱的问题,
1>同session的事件执行顺序,不能保证,
2>程序员写业务时对locker的使用不规范,多对象修改时考虑不全,但是单线程有序执行,就可以解决这些问题,但对不同session导致数据交叉是没作用的,那个还得依赖locker
2.考虑两个问题
1>session队列的长度要可控,所以要改造一下,见上面MyOrderedThreadPoolExecutor 红色代码部分
2>线程初始数量的上限的定义选值
3>ExecutorFilter提供了业务逻辑的执行线程,可以将应用层业务逻辑通过配置该filter在配置的线程池内执行
/**
* 消息执行器线程池的最小线程数
*/
private int corePoolSize = Runtime.getRuntime().availableProcessors() * 4; /**
* 消息执行器线程池的最大线程数,读写分开是为了防止大量的读请求阻塞回写
*/
private int maxPoolSize = Runtime.getRuntime().availableProcessors() * 24 + 1; /**
* 消息执行器线程池超过corePoolSize的Thread存活时间;秒
*/
private long keepAliveTime = 300;
/**
* useOrderedPool=true的时候有效,指定一个session的请求队列的最大长度,超过这个长度的请求丢弃.
*/
private int orderedPoolMaxQueueSize = 20;
略。。。。。 ThreadPoolExecutor executor = new MyOrderedThreadPoolExecutor(corePoolSize,
maxPoolSize, keepAliveTime, TimeUnit.SECONDS,
new NamingThreadFactory("WolfServerThread"),
ioEventQueueHandler, orderedPoolMaxQueueSize); // 这里是预先启动corePoolSize个处理线程
executor.prestartAllCoreThreads(); //这里指定的监听事件就会由这里指定的线程池来处,而不在是processr线程来处理
chain.addLast("exec", new ExecutorFilter(executor,
IoEventType.EXCEPTION_CAUGHT, IoEventType.MESSAGE_RECEIVED,
IoEventType.SESSION_CLOSED, IoEventType.SESSION_IDLE,
IoEventType.SESSION_OPENED));
一篇好文章讲ExecutorFilter http://www.blogjava.net/landon/archive/2014/02/03/409521.html
【MINA】OrderedThreadPoolExecutor和UnorderedThreadPoolExecutor的事件监听线程池的选择的更多相关文章
- Java中用得比较顺手的事件监听
第一次听说监听是三年前,做一个webGIS的项目,当时对Listener的印象就是个"监视器",监视着界面的一举一动,一有动静就触发对应的响应. 一.概述 通过对界面的某一或某些操 ...
- 4.JAVA之GUI编程事件监听机制
事件监听机制的特点: 1.事件源 2.事件 3.监听器 4.事件处理 事件源:就是awt包或者swing包中的那些图形用户界面组件.(如:按钮) 事件:每一个事件源都有自己特点有的对应事件和共性事件. ...
- Node.js 教程 05 - EventEmitter(事件监听/发射器 )
目录: 前言 Node.js事件驱动介绍 Node.js事件 注册并发射自定义Node.js事件 EventEmitter介绍 EventEmitter常用的API error事件 继承EventEm ...
- .NET事件监听机制的局限与扩展
.NET中把“事件”看作一个基本的编程概念,并提供了非常优美的语法支持,对比如下C#和Java代码可以看出两种语言设计思想之间的差异. // C#someButton.Click += OnSomeB ...
- 让 select 的 option 标签支持事件监听(如复制操作)
这标题,让option支持事件监听,应该不难的呀,有什么好讲的? 其实还是有的,默认在浏览器代码是无法直接对option标签进行操作的,不仅包括JS事件监听,还是CSS样式设置 查了一些资料,姑且认为 ...
- [JS]笔记12之事件机制--事件冒泡和捕获--事件监听--阻止事件传播
-->事件冒泡和捕获-->事件监听-->阻止事件传播 一.事件冒泡和捕获 1.概念:当给子元素和父元素定义了相同的事件,比如都定义了onclick事件,点击子元素时,父元素的oncl ...
- [No00006A]Js的addEventListener()及attachEvent()区别分析【js中的事件监听】
1.添加时间监听: Chrom中: addEventListener的使用方式: target.addEventListener(type, listener, useCapture); target ...
- java 事件监听 - 鼠标
java 事件监听 - 鼠标 //事件监听 //鼠标事件监听 //鼠标事件监听有两个实现接口 //1.MouseListener 普通的鼠标操作 //2.MouseMotionListener 鼠标的 ...
- java 事件监听 - 键盘
java 事件监听 - 键盘 //事件监听 //键盘事件监听,写了一个小案例,按上下左右,改变圆形的位置,圆形可以移动 import java.awt.*; import javax.swing.*; ...
随机推荐
- 教程-Delphi编译就报毒
这几天都在忙专周实验,今天用到delphi,一到编译时nod32就报毒,编译空文件也报毒,上网查了资料才明白,是编译文件被感染了,生成软件就会报毒.把自己找到的资料分享如下: 重新编译时,生成的e ...
- 【C语言】-循环结构-while语句
while语句: while循环可实现"当型"循环,即当条件成立时,执行循环体.适合无法确定循环执行次数的情况. while (表达式) { 循环语句 } 注意: 表达式为循环控制 ...
- STM32硬件调试详解
STM32的基本系统主要涉及下面几个部分: 一.电源 1).无论是否使用模拟部分和AD部分,MCU外围出去VCC和GND,VDDA.VSSA.Vref(如果封装有该引脚)都必需要连接,不可悬空: 2) ...
- iOS动画实现总结
在iOS中,动画实现方向有两种,一种是操作UIView的animation方法,另外一种就是核心动画,但到iOS7中,UIView又跟核心动画牵扯在一起. 方式一(利用核心动画添加动画) 核心动画的层 ...
- 也谈SSO,一个简单实用的单点登录Demo
关于SSO(单点登录),百度百科解释如下 : “SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.它包括可以将这次主要 ...
- Oracle- PL/SQL DEV工具的使用收集
1.工具---首选项---用户界面---编辑器----定制关键词 里面可以选择关键字是否大写 2.美化代码段,点击菜单edit,然后pl/sql beautifer,快捷键:PL/SQL Develo ...
- NSTimer运行机制和线程问题
A.首先要理解NSTimer运行机制和Runloop之间的关系: 1.IOS的Run Loops机制 Run Loops是线程的基础部份,任何线程,包括主结程,都包含了一个run loop对象,Coc ...
- MFC 学习 之 状态栏的添加
1.首先声明一个 CStatusBar m_bar;//声明对象2.然后打开视图资源 String Table中添加两个字段值 3.创建了两个字段值以后,在OnintDialog() 所在的 .cp ...
- libpq程序例子
程序: [root@lex tst]# cat testlibpq.c /* * testlibpq.c * Test the C version of LIBPQ, the POSTGRES fro ...
- Sublime Text 超好用的侧栏插件SideBarEnhancements
SideBarEnhancements插件有效地改进了Sublime Text的侧边栏.安装插件后在侧边栏上点击右键,可以找到一下新功能:在资源管理器中打开.新建文件.新建文件夹.以…打开.在浏览器中 ...