读书人

MINA2为什么取消了ThreadModel

发布时间: 2012-09-07 10:38:15 作者: rapoo

MINA2为何取消了ThreadModel

在MINA2的官方文档中,apache提到了ThreadModel被废除,原因是该类的使用容易引起错误。由于我一开始就用的是mina2,所以对这个问题没什么想法。

?

ThreadModel的作用其实就是在处理链的最后(handler之前)添加一个ExecutorFilter过滤器。

?

前年我进入了现在的项目组,组里由于使用mina比较早,因此在使用mina1.1.7,并且对该mina进行了封装使其更易用(在我看来,封装的主要原因在于对mina的API为操作链不太习惯,而将它封装为添加连接池、添加解码器等API,我使用起来觉得比mina的API还有点麻烦),但是正式1.X版本的ThreadModel引起了问题,才让我对他的废除有点感想。

?

mina1.X中的ThreadModel使用有两种方式,一种为采用手动方式设置连接池:

SocketAcceptorConfig acceptorConfig = acceptor.getDefaultConfig();acceptorConfig.setThreadModel(ThreadModel.MANUAL);

?

?

另外一种为使用默认ThreadModel设置连接池:

((ExecutorThreadModel)acceptorConfig.cfg.getThreadModel()).setExecutor(executor);

?

正常情况下,第二种情况没什么问题,但是如果你的程序中启动两个或两个以上的server,并且连接池的设置都使用第二种方式,那就悲剧了。

?

我们来看一下SocketAcceptorConfig类的getThreadModel方法,内容如下:

?

public ThreadModel getThreadModel() {        if (threadModel == null) {            threadModel = getDefaultThreadModel();        }        return threadModel;    }

?

?

由于采用默认ThreadModel,我们是没有设置过ThreadModel的,所以会调用getDefaultThreadModel方法,再来看看这个方法的代码:

?

private synchronized ThreadModel getDefaultThreadModel() {        if (defaultThreadModel == null) {            defaultThreadModel = ExecutorThreadModel.getInstance("AnonymousIoService");        }        return defaultThreadModel;    }

?

?

看到了吧, ExecutorThreadModel.getInstance("AnonymousIoService")这句,如果信息的人可能会知道悲剧在什么地方了,让我们接着看看这个语句中方法是什么样的

?

private static final Map<String, ExecutorThreadModel> service2model = new HashMap<String, ExecutorThreadModel>();public static ExecutorThreadModel getInstance(String serviceName) {        if (serviceName == null) {            throw new NullPointerException("serviceName");        }        ExecutorThreadModel model;        synchronized (service2model) {            model = service2model.get(serviceName);            if (model == null) {                model = new ExecutorThreadModel(serviceName);                service2model.put(serviceName, model);            }        }        return model;    }

?

在代码中我们可以看到,service2model是一个静态变量,ExecutorThreadModel.getInstance("AnonymousIoService")拿到的ExecutorThreadModel也是一个静态变量,那么当两个server都没有acceptorConfig.setThreadModel时,两个server会共用同一个ExecutorThreadModel(名为AnonymousIoService的那个)。

当一个server业务量大设置了一个100大小的线程池,而另外一个server业务量小设置了大小为2的线程池,而业务小的server启动晚于业务大的server,那么业务小的线程池就会覆盖了业务大的线程池。

?

??? 我觉得还是老老实实的在链后面添加ExecutorFilter比较靠谱。

?

SocketAcceptor acceptor = ...;DefaultIoFilterChainBuilder filterChainBuilder = acceptor.getDefaultConfig().getFilterChain();filterChainBuilder.addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool());

?

?

恩恩。

读书人网 >软件架构设计

热点推荐