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. 50道经典的JAVA编程题(26-30)

    50道经典的JAVA编程题(26-30),这么晚了,早点睡了要,明早8点考java祝我好运吧!!!晚安~ [程序26]Ex26.java(跳过了,好没意思的题啊)题目:请输入星期几的第一个字母来判断一 ...

  2. leetcode@ [303/304] Range Sum Query - Immutable / Range Sum Query 2D - Immutable

    https://leetcode.com/problems/range-sum-query-immutable/ class NumArray { public: vector<int> ...

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

    CM repo库info;

  4. Getty – Java NIO 框架设计与实现

    前言 Getty是我为了学习 Java NIO 所写的一个 NIO 框架,实现过程中参考了 Netty 的设计,同时使用 Groovy 来实现.虽然只是玩具,但是麻雀虽小,五脏俱全,在实现过程中,不仅 ...

  5. 设置Windows 远程协助与远程桌面

    家庭局域网组建完成后,即可通过远程协助解决各种问题,或联机玩游戏等. 使用Windows 7\8\10 远程协助与远程桌面 Windows 8系统中自带了远程协助功能,家庭用户只需要做简单的设置,就可 ...

  6. hdoj 1863 畅通工程

    并查集+最小生成树 畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  7. STM32 SysTick定时器应用【worldsing笔记】

    SysTick是CM内核独立的定时器,时钟可以用内核内部的,也可以用芯片厂家(ST)的时钟,参考<Cortex-M3权威指南>的第13章: 另外也可以考<STM32F10xxx Co ...

  8. UVa 127 - "Accordian" Patience

    题目:52张扑克,从左到右在平面上排列,按着如下规则处理: 1.按照从左到右的顺序,如果一张牌和左边的第一张或者第三张匹配,就把它放到对应的牌上面. 2.如果可以移动到多个位置,移动到最左端的牌上面. ...

  9. xampp配置host和httpd可以随意访问任何本机的地址

    1.修改host 不管你用的是什么系统,windows, mac,电脑上都会有一个 hosts 文件,修改这个文件,可以改变主机名所对应的 ip 地址.比如你安装了 Web 开发环境(MAMP 或 W ...

  10. 委托、匿名函数、Lambda表达式和事件的学习

    委托: 还记得C++里的函数指针么?大家可以点击这里查看一下以前的笔记.C#的委托和C++中的函数指针效果一致. 当我们需要将函数作为对象进行传递和使用时就需要用到委托. 下面我们看一个例子: usi ...