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的事件监听线程池的选择的更多相关文章

  1. Java中用得比较顺手的事件监听

    第一次听说监听是三年前,做一个webGIS的项目,当时对Listener的印象就是个"监视器",监视着界面的一举一动,一有动静就触发对应的响应. 一.概述 通过对界面的某一或某些操 ...

  2. 4.JAVA之GUI编程事件监听机制

    事件监听机制的特点: 1.事件源 2.事件 3.监听器 4.事件处理 事件源:就是awt包或者swing包中的那些图形用户界面组件.(如:按钮) 事件:每一个事件源都有自己特点有的对应事件和共性事件. ...

  3. Node.js 教程 05 - EventEmitter(事件监听/发射器 )

    目录: 前言 Node.js事件驱动介绍 Node.js事件 注册并发射自定义Node.js事件 EventEmitter介绍 EventEmitter常用的API error事件 继承EventEm ...

  4. .NET事件监听机制的局限与扩展

    .NET中把“事件”看作一个基本的编程概念,并提供了非常优美的语法支持,对比如下C#和Java代码可以看出两种语言设计思想之间的差异. // C#someButton.Click += OnSomeB ...

  5. 让 select 的 option 标签支持事件监听(如复制操作)

    这标题,让option支持事件监听,应该不难的呀,有什么好讲的? 其实还是有的,默认在浏览器代码是无法直接对option标签进行操作的,不仅包括JS事件监听,还是CSS样式设置 查了一些资料,姑且认为 ...

  6. [JS]笔记12之事件机制--事件冒泡和捕获--事件监听--阻止事件传播

    -->事件冒泡和捕获-->事件监听-->阻止事件传播 一.事件冒泡和捕获 1.概念:当给子元素和父元素定义了相同的事件,比如都定义了onclick事件,点击子元素时,父元素的oncl ...

  7. [No00006A]Js的addEventListener()及attachEvent()区别分析【js中的事件监听】

    1.添加时间监听: Chrom中: addEventListener的使用方式: target.addEventListener(type, listener, useCapture); target ...

  8. java 事件监听 - 鼠标

    java 事件监听 - 鼠标 //事件监听 //鼠标事件监听 //鼠标事件监听有两个实现接口 //1.MouseListener 普通的鼠标操作 //2.MouseMotionListener 鼠标的 ...

  9. java 事件监听 - 键盘

    java 事件监听 - 键盘 //事件监听 //键盘事件监听,写了一个小案例,按上下左右,改变圆形的位置,圆形可以移动 import java.awt.*; import javax.swing.*; ...

随机推荐

  1. sql-逻辑循环while if

    --计算1-100的和 declare @int int=1; declare @total int=0; while(@int<=100) begin set @total=@total+@i ...

  2. window2008 64位系统没有office组件问题分析及解决

    服务器是windows server2008 64位系统, 我的系统需要用到Microsoft.Office.Interop.Excel组件 在上传Excel单据遇到错误:检索 COM 类工厂中 CL ...

  3. linux命令getopts

    一.getopts 简介 由于shell命令行的灵活性,自己编写代码判断时,复杂度会比较高.使用内部命令 getopts 可以很方便地处理命令行参数.一般格式为: getopts options va ...

  4. maven 名词

    maven 坐标: 坐标 其实就是 通过几种不同的元素描述来找到其对应的构件. maven 定义坐标的元素有: 1. groupId : 定义当前maven 项目隶属的实际项目,一般是域名的反向写法 ...

  5. CM 部署bigdata测试环境群集机器报错

    CM repo库info;

  6. input输入密码变黑点密文

    input输入密码加密 html代码 <form id="login-form" method="post" onsubmit="return ...

  7. flex开发小技巧集锦

    关于flex开发网上有非常多的相关信息介绍,因此我们要想学习关于flex开发的知识信息技能是一件非常简单和方便的事情.而针对于flex开发小编要告诉大家的是一些flex开发小技巧.利用这些小技巧能够有 ...

  8. MySQL 索引、视图、DML

    1.索引 索引是存放在模式(schema)中的一个数据库对象,索引的作用就是提高对表的检索查询速度, 索引是通过快速访问的方法来进行快速定位数据,从而减少了对磁盘的读写操作. 索引是数据库的一个对象, ...

  9. centos上安装jdk环境

    老沙采用的环境是centos 6.5 64位服务器.在linux上安装jdk环境都很多中方式,这里讲解下手工进行安装并进行环境变量配置. 首先需要下载一个64位版本的linux,可以去oracle官网 ...

  10. android 处理网络状态——无网,2g,3g,wifi,ethernet,other

    今天在一位很牛逼的学长的博客里面看到了这段代码后,很是激动啊,于是就“偷”了过来,嘿嘿....为自己也为更多需要它的程序媛 直接上代码: public class GetNetWorkStateAct ...