3、增加一个ExecutorFilter到IoFilterChain中 ExecutorFilter是一个IoFilter,用于将进入的I/O事件转到一个 java.util.concurrent.Executor实现。事件会从这个Executor转到下一个IoFilter,通常是一个线程池。可以在 IoFilterChain的任何地方增加任意数目的ExecutorFilter,实现任何类型的线程模型,从简单的线程池到复杂的SEDA。 到现在为止我们还没有增加ExecutorFilter,如果没有增加ExecutorFilter,事件会通过方法调用转到一个 IoHandler,这意味着在IoHandler实现中的业务逻辑会在I/O处理线程里运行。我们叫这种线程模型为"单线程模型"。单线程模型可以用来就会低反应网络应用程序,受CPU限制的业务逻辑(如,游戏服务器)。 典型的网络应用需要一个ExecutorFilter插入到IoFilterChain中,因为业务逻辑和I/O处理线程有不同的资源使用模式。如果你用IoHandler的实现来执行数据库操作,而没有增加一个ExecutorFilter的话,那么,你整个服务器会在执行数据库操作的时候锁定,特别是数据库性能低的时候。下面的例子配置一个IoService在一个新的IoSession建立时增加一个ExecutorFilter。 IoAcceptor acceptor = ...; DefaultIoFilterChainBuilder filterChainBuilder = acceptor.getDefaultConfig().getFilterChain(); filterChainBuilder.addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()); 这里要注意ExecutorFilter没有管理特定的Executor的生命周期,当完成时,需要关闭所有特定Executor的工作线程。 ExecutorService executor = ...; IoAcceptor acceptor = ...; DefaultIoFilterChainBuilder filterChainBuilder = acceptor.getDefaultConfig().getFilterChain(); filterChainBuilder.addLast("threadPool", new ExecutorFilter(executor); // Start the server. acceptor.bind(...); // Shut down the server. acceptor.unbind(...); executor.shutdown(); 使用一个ExecutorFilter通常不意味着要用一个线程池,对于Executor的实现没有任何限制。
4、应该把ExecutorFilter放在IoFilterChain的什么地方 这个要根据于具体应用的情况来定。如果一个应用有一个ProtocolCodecFilter实现和一个常用的有数据库操作的IoHandler实现的话,那么就建议在ProtocolCodecFilter实现的后面增加一个ExecutorFilter,这是因为大部分的协议解码实现的性能特性是受CPU限制的,和I/O处理线程是一样的。 IoAcceptor acceptor = ...; DefaultIoFilterChainBuilder filterChainBuilder = acceptor.getDefaultConfig().getFilterChain(); // Add CPU-bound job first, filterChainBuilder.addLast("codec", new ProtocolCodecFactory(...)); // and then a thread pool. filterChainBuilder.addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool());