mina坑之OrderedThreadPoolExecutor

现象:
客户端消息只能到解码器,到不了IOHandler


MINA启动代码片段如下:

IoFilter protocol = new ProtocolCodecFilter(codecFactory);
fcb.addLast("codec", protocol);

OrderedThreadPoolExecutor threadpoll = new OrderedThreadPoolExecutor(500);
fcb.addLast("threadPool", new ExecutorFilter(threadpoll));


为了多线程处理,在解码器的下面,我们加了一个线程池,mina自己写的线程池, 这个线程池的作用是对于同一个session来的请求,它能够按照请求到达的时间顺序的执行。举个例子,在一个session中,如果先接收到request A,然后再接收到request B,那么,OrderedThreadPoolExecutor能够保证一定处理完A之后再处理B。而一般的thread pool,会将A和B传递给不同的thread处理,有可能request B会先于request A完成。

为什么消息能过解码器,但是到不了逻辑, 怀疑这个线程池出问题,我简单分析一下这个类的源码:


private final Set<Worker> workers = new HashSet<Worker>();

private final AtomicInteger idleWorkers = new AtomicInteger();


workers是一个Worker的集合,每一个Worker都实现了Runnable接口,线程池管理这些Worker线程执行并发的事件处理, idleWorkers则负责及时的统计空闲的Worker数量便于提高性能, 非常形象的命名,workers是一个工厂,里面全部是worker工人,工人负责处理扔过来的Runnable, idleWrokers统计有多少工人空闲, 很显然,idleWorkers的数量必然小于等于workers的数量

private void addWorkerIfNecessary() {
if (idleWorkers.get() == 0) {
synchronized (workers) {
if (workers.isEmpty() || (idleWorkers.get() == 0)) {
addWorker();
}
}
}
}

这个方法是专门给workers添加worker的,但是大家注意,在加之前有个判断,如果idleWrokers大于0肯定就加不进去了

也就是说,如果我们的workers里数量是0了,但是idleWorkers计数却大于0,那这个线程池肯定跪了

问题就出现在下面这段代码:


public void run() {
thread = Thread.currentThread();

try {
for (;;) {
IoSession session = fetchSession();

idleWorkers.decrementAndGet();

if (session == null) {
synchronized (workers) {
if (workers.size() > getCorePoolSize()) {
// Remove now to prevent duplicate exit.
workers.remove(this);
break;
}
}
}

if (session == EXIT_SIGNAL) {
break;
}

try {
if (session != null) {
runTasks(getSessionTasksQueue(session));
}
} finally {
idleWorkers.incrementAndGet();
}
}
} finally {
synchronized (workers) {
workers.remove(this);
OrderedThreadPoolExecutor.this.completedTaskCount += completedTaskCount;
workers.notifyAll();
}
}
}

上面的是worker的run方法,

这段代码什么情况下会导致 workers里数量是0,但idleWorkers计数却大于0的情况呢

代码看起来似乎不会出现这种情况,因为能出异常的地方,都进行了try处理,

问题恰恰就发生在try里,假如我们的worker里有一个Runnable里出现一个Throwable的异常呢

当代码运行到这行时

runTasks(getSessionTasksQueue(session));

这里抛出了一个Throwable的异常,代码里没有处理,所以导致for循环直接退出,到了最后的finally

于是出现了我们不愿意看到的情况,workers数量比idleWorkers少了1,这个异常发生几次,就会导致workers是0,而idleWorkers数量大于0

这时候再有Runnable过来,全部都执行不了了

让我们来看看咱们的JDK的线程池这个地方是怎么做的,会不会出现同样的情况呢


try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}

哈哈哈,看来JDK还是牛逼些,所有错误全部处理了

总结一下,mina这个地方确实是个坑,但是如果框架里try了Throwable也不会出现这个问题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值