现象:
客户端消息只能到解码器,到不了IOHandler
MINA启动代码片段如下:
为了多线程处理,在解码器的下面,我们加了一个线程池,mina自己写的线程池, 这个线程池的作用是对于同一个session来的请求,它能够按照请求到达的时间顺序的执行。举个例子,在一个session中,如果先接收到request A,然后再接收到request B,那么,OrderedThreadPoolExecutor能够保证一定处理完A之后再处理B。而一般的thread pool,会将A和B传递给不同的thread处理,有可能request B会先于request A完成。
为什么消息能过解码器,但是到不了逻辑, 怀疑这个线程池出问题,我简单分析一下这个类的源码:
workers是一个Worker的集合,每一个Worker都实现了Runnable接口,线程池管理这些Worker线程执行并发的事件处理, idleWorkers则负责及时的统计空闲的Worker数量便于提高性能, 非常形象的命名,workers是一个工厂,里面全部是worker工人,工人负责处理扔过来的Runnable, idleWrokers统计有多少工人空闲, 很显然,idleWorkers的数量必然小于等于workers的数量
这个方法是专门给workers添加worker的,但是大家注意,在加之前有个判断,如果idleWrokers大于0肯定就加不进去了
也就是说,如果我们的workers里数量是0了,但是idleWorkers计数却大于0,那这个线程池肯定跪了
问题就出现在下面这段代码:
上面的是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的线程池这个地方是怎么做的,会不会出现同样的情况呢
哈哈哈,看来JDK还是牛逼些,所有错误全部处理了
总结一下,mina这个地方确实是个坑,但是如果框架里try了Throwable也不会出现这个问题
客户端消息只能到解码器,到不了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也不会出现这个问题