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. 【转】Spark是基于内存的分布式计算引擎

    Spark是基于内存的分布式计算引擎,以处理的高效和稳定著称.然而在实际的应用开发过程中,开发者还是会遇到种种问题,其中一大类就是和性能相关.在本文中,笔者将结合自身实践,谈谈如何尽可能地提高应用程序 ...

  2. 搭建Discuz! (mysql+apache+Discuz! )

    0. 配置环境 0.0 安装apache 0.1 安装php 1.数据库准备 1.1 创建数据库用户 1.2 创建discuz使用的数据库(编码:utf8-general-ci) 1.3 把1.2创建 ...

  3. 第十三章、学习 Shell Scripts 简单的 shell script 练习

    简单的 shell script 练习 简单范例 对谈式脚本:变量内容由使用者决定 [root@www scripts]# vi sh02.sh #!/bin/bash # Program: # Us ...

  4. web开发工具类

    1.日期工具类 import java.text.SimpleDateFormat; import java.util.Date; public class DateUtil { public sta ...

  5. 本地开发 localhost链接数据库比127.0.0.1慢

    自己手写一段代码的时候发现一个问题  链接数据库的时候 用 127.0.0.1比localhost明显的快,localhost要等一下才会有响应 而127.0.0.1就是瞬间响应.一番排查,发现了一个 ...

  6. 剑指OFFER之字符串的排列(九度OJ1369)

    题目描述: 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入: 每个 ...

  7. 利用接口做参数,写个计算器,能完成+-*/运算 (1)定义一个接口Compute含有一个方法int computer(int n,int m); (2)设计四个类分别实现此接口,完成+-*/运算 (3)设计一个类UseCompute,含有方法: public void useCom(Compute com, int one, int two) 此方法要求能够:1.用传递过来的对象调用compute

    package com.homework5; public interface Compute { //声明抽象方法 int computer(int n,int m); } package com. ...

  8. SQLite使用教程5 分离数据库

    http://www.runoob.com/sqlite/sqlite-detach-database.html SQLite 分离数据库 SQLite的 DETACH DTABASE 语句是用来把命 ...

  9. Android adt v22.6.2-1085508 自己主动创建 appcompat_v7 解决方法,最低版本号2.2也不会出现

    Android 开发工具升级到22.6.2在创建project时仅仅要选择的最低版本号低于4.0,就会自己主动生成一个项目appcompat_v7,没创建一个新的项目都会自己主动创建,非常是烦恼... ...

  10. 读取XML帮助类

    using System; using System.Data; using System.Configuration; using System.Linq; using System.Web; us ...