mina的ExecutorFilter使用方式 博客分类: nio minaExecutorFilter
程序员文章站
2024-02-23 11:50:46
...
昨天群里讨论mina的ExecutorFilter,有点不明白的地方,早上看了下mina的ExecutorFilter源码,感觉主要逻辑还是很简单的。
源码头的注释:
/** 38 * A filter that forwards I/O events to {@link Executor} to enforce a certain 39 * thread model while allowing the events per session to be processed 40 * simultaneously. You can apply various thread model by inserting this filter 41 * to a {@link IoFilterChain}.*/ 1.该过滤器,使用特定的线程模型,使每个session的evens得以同时执行,线程模型可定制。 (就是你可以指定线程池类型) 42 /* 43 * <h2>Life Cycle Management</h2> 44 * 45 * Please note that this filter doesn't manage the life cycle of the {@link Executor}. 46 * If you created this filter using {@link #ExecutorFilter(Executor)} or similar 47 * constructor that accepts an {@link Executor} that you've instantiated, you have 48 * full control and responsibility of managing its life cycle (e.g. calling 49 * {@link ExecutorService#shutdown()}. 50 * <p> 51 * If you created this filter using convenience constructors like 52 * {@link #ExecutorFilter(int)}, then you can shut down the executor by calling 53 * {@link #destroy()} explicitly. 54 */ 2.生命周期管理: 注意:ExecutorFilter不负责线程池的生命周期管理,你自己负责 55 /* <h2>Event Ordering</h2> 56 * 57 * All convenience constructors of this filter creates a new 58 * {@link OrderedThreadPoolExecutor} instance. Therefore, the order of event is 59 * maintained like the following: 60 * <ul> 61 * <li>All event handler methods are called exclusively. 62 * (e.g. messageReceived and messageSent can't be invoked at the same time.)</li> 63 * <li>The event order is never mixed up. 64 * (e.g. messageReceived is always invoked before sessionClosed or messageSent.)</li> 65 * </ul> 66 * However, if you specified other {@link Executor} instance in the constructor, 67 * the order of events are not maintained at all. This means more than one event 68 * handler methods can be invoked at the same time with mixed order. For example, 69 * let's assume that messageReceived, messageSent, and sessionClosed events are 70 * fired. 71 * <ul> 72 * <li>All event handler methods can be called simultaneously. 73 * (e.g. messageReceived and messageSent can be invoked at the same time.)</li> 74 * <li>The event order can be mixed up. 75 * (e.g. sessionClosed or messageSent can be invoked before messageReceived 76 * is invoked.)</li> 77 * </ul> 78 * If you need to maintain the order of events per session, please specify an 79 * {@link OrderedThreadPoolExecutor} instance or use the convenience constructors. 80 */ 3.event顺序 默认线程池为OrderedThreadPoolExecutor,因此,管理event顺序如下: 1. 任何event处理方法是排它的,比如messageReceived和messageSent不可能同时执行。 2. event顺序不可能混淆,比如messageReceived一般先于sessionClosed或messageSent. 如果你不使用OrderedThreadPoolExecutor,event的顺序会变得混乱: 1. 所有的event处理方法可能会同时执行。 2. event顺序变得混乱,比如sessionClosed或者messageSent先于messageReceived执行 总之,如果你想每个session的event变得有序,请使用默认的线程池:) (不用的话好像后果很严重呵呵) 81 /* <h2>Selective Filtering</h2> 82 * 83 * By default, all event types but <tt>sessionCreated</tt>, <tt>filterWrite</tt>, 84 * <tt>filterClose</tt> and <tt>filterSetTrafficMask</tt> are submitted to the 85 * underlying executor, which is most common setting. 86 * <p> 87 * If you want to submit only a certain set of event types, you can specify them 88 * in the constructor. For example, you could configure a thread pool for 89 * write operation for the maximum performance: 90 * <pre><code> 91 * IoService service = ...; 92 * DefaultIoFilterChainBuilder chain = service.getFilterChain(); 93 * 94 * chain.addLast("codec", new ProtocolCodecFilter(...)); 95 * // Use one thread pool for most events. 96 * chain.addLast("executor1", new ExecutorFilter()); 97 * // and another dedicated thread pool for 'filterWrite' events. 98 * chain.addLast("executor2", new ExecutorFilter(IoEventType.WRITE)); 99 * </code></pre> 100 */ 4.选择性过滤 默认情况下,所有的event,除了sessionCreated之外,都会交给线程池去执行处理。 但是如果你只想把某些event交给线程池,那可以这么做: IoService service = ...; DefaultIoFilterChainBuilder chain = service.getFilterChain(); chain.addLast("codec", new ProtocolCodecFilter(...)); // 使用这个线程池处理大部分event chain.addLast("executor1", new ExecutorFilter()); // 使用这个线程池处理filterWrite这个event chain.addLast("executor2", new ExecutorFilter(IoEventType.WRITE));
ExecutorFilter可以针对特定的event交给线程池执行,这点比较灵活,看下messageReceived的处理:
public final void messageReceived(NextFilter nextFilter, IoSession session, Object message) { if (eventTypes.contains(IoEventType.MESSAGE_RECEIVED)) { IoFilterEvent event = new IoFilterEvent(nextFilter, IoEventType.MESSAGE_RECEIVED, session, message); fireEvent(event); } else { nextFilter.messageReceived(session, message); } }
1.检查该event是否要交给线程执行.
2.将它封装成IoFilterEvent
3.提交线程池
fireEvent(event);
protected void fireEvent(IoFilterEvent event) { executor.execute(event); }
来看看IoFilterEvent的fire方法(其实就是Runnable的run)
switch (type) { case MESSAGE_RECEIVED: Object parameter = getParameter(); nextFilter.messageReceived(session, parameter); break;
所以,如果使用了ExecutorFilter,在它之后的过滤器(nextFilter),以及handler,都会放在线程池中去执行,注意到粒度是event,当然默认是全部event。如此IO线程可摆脱其它业务逻辑,提升对客户端的响应效率。
另外,ExecutorFilter中的默认OrderedThreadPoolExecutor,最好还是不要替代,个人看法。