源码研读-mina多线程模型
来源:互联网 发布:初中女生内衣淘宝 编辑:程序博客网 时间:2024/05/16 14:48
mina是目前很流行的一个网络应用框架,用以帮助用户构建高性能和高伸缩性的网络应用。称其为网络应用框架,主要是其极强的扩展性,支持包括http,ssh,ftp等在内的多种应用层协议。而它本身封装了底层的TCP, UDP等通信协议,使用也非常方便。本文的重点是分析源码,了解它的多线程模型。源码版本为apache-mina-2.0.7。
为了有助于理解,先简单介绍一下mina的整体架构。如下图所示,其分为三层。在通信层之上,是IOService,提供IO服务,管理连接信息,它包含两个实现,一个是IOAcceptor,位于服务器,一个是IOConnector,处在客户端。在IOService之上,是IOFilterChain,作为一个容器,包含一系列IOFilter,做一些通用的数据处理,像协议的转换,多线程,日志等。最上层是IOHandler,负责执行用户的业务逻辑。
(来源http://mina.apache.org/mina-project/userguide/ch2-basics/application-architecture.html)
下面将按照服务器启动,连接监听,IO处理的顺序来对mina的多线程框架展开分析。
由此看来,mina对多线程的控制是非常精细的,尤其是IO处理线程与连接监听线程的分离,设计相当巧妙,值得学习。
为了有助于理解,先简单介绍一下mina的整体架构。如下图所示,其分为三层。在通信层之上,是IOService,提供IO服务,管理连接信息,它包含两个实现,一个是IOAcceptor,位于服务器,一个是IOConnector,处在客户端。在IOService之上,是IOFilterChain,作为一个容器,包含一系列IOFilter,做一些通用的数据处理,像协议的转换,多线程,日志等。最上层是IOHandler,负责执行用户的业务逻辑。
(来源http://mina.apache.org/mina-project/userguide/ch2-basics/application-architecture.html)
下面将按照服务器启动,连接监听,IO处理的顺序来对mina的多线程框架展开分析。
protected final Set<SocketAddress> bindInternal(List<? extends SocketAddress> localAddresses) throws Exception { .... // cr eates the Acceptor instance and has the local // executor kick it off. startupAcceptor(); ..... } private void startupAcceptor() throws InterruptedException { ...... // start the acceptor if not already started Acceptor acceptor = acceptorRef.get(); if (acceptor == null) { lock.acquire(); acceptor = new Acceptor(); if (acceptorRef.compareAndSet(null, acceptor)) { executeWorker(acceptor); } else { lock.release(); } } } protected final void executeWorker(Runnable worker, String suffix) { String actualThreadName = threadName; if (suffix != null) { actualThreadName = actualThreadName + '-' + suffix; } executor.execute(new NamePreservingRunnable(worker, actualThreadName)); }
服务启动时,创建了一个Acceptor实例并在后台运行。Acceptor 主要用来监听用户的连接请求,看看代码:
private class Acceptor implements Runnable { public void run() { ...... while (selectable) { try { // Detect if we have some keys ready to be processed // The select() will be woke up if some new connection // have occurred, or if the selector has been explicitly // woke up int selected = select(); // this actually sets the selector to OP_ACCEPT, // and binds to the port on which this class will // listen on nHandles += registerHandles(); // Now, if the number of registred handles is 0, we can // quit the loop: we don't have any socket listening // for incoming connection. if (nHandles == 0) { ...... } if (selected > 0) { // We have some connection request, let's process // them here. processHandles(selectedHandles()); } // check to see if any cancellation request has been made. nHandles -= unregisterHandles(); } catch (ClosedSelectorException cse) { ...... } } ...... } /** * This method will process new sessions for the Worker class. All * keys that have had their status updates as per the Selector.selectedKeys() * method will be processed here. Only keys that are ready to accept * connections are handled here. * <p/> * Session objects are created by making new instances of SocketSessionImpl * and passing the session object to the SocketIoProcessor class. */ @SuppressWarnings("unchecked") private void processHandles(Iterator<H> handles) throws Exception { while (handles.hasNext()) { H handle = handles.next(); handles.remove(); // Associates a new created connection to a processor, // and get back a session S session = accept(processor, handle); if (session == null) { continue; } initSession(session, null, null); // add the session to the SocketIoProcessor session.getProcessor().add(session); } } }Acceptor在监听到有连接时,创建了一个Session,并把该Session添加到IOProcessor的队列中。IOProcessor用来处理读写请求。为了进一步提高系统的性能,这里的IOProcessor默认实现为SimpleIOProcessorPool,池的大小默认为系统内核数+1。SimpleIOProcessorPool选择一个IOProcessor来进一步处理读写请求,代码如下:
public final void add(S session) { getProcessor(session).add(session); } /** * Find the processor associated to a session. If it hasen't be stored into * the session's attributes, pick a new processor and stores it. */ @SuppressWarnings("unchecked") private IoProcessor<S> getProcessor(S session) { IoProcessor<S> processor = (IoProcessor<S>) session.getAttribute(PROCESSOR); if (processor == null) { if (disposed || disposing) { throw new IllegalStateException("A disposed processor cannot be accessed."); } processor = pool[Math.abs((int) session.getId()) % pool.length]; if (processor == null) { throw new IllegalStateException("A disposed processor cannot be accessed."); } session.setAttributeIfAbsent(PROCESSOR, processor); } return processor; }可以看出SimpleIOProcessorPool只是以简单轮转的方式来选择一个IOProcessor来处理Session。对于复杂的应用,也可以针对自己应用的特点定制IOProcessor。另外,值得注意的是,该Session与一个IOProcessor绑在了一起,这样实际的读写请求就只会在同一个线程内,避免了线程之间的同步。继续看IOProcessor的处理:
public final void add(S session) { if (disposed || disposing) { throw new IllegalStateException("Already disposed."); } // Adds the session to the newSession queue and starts the worker newSessions.add(session); startupProcessor(); } /** * Starts the inner Processor, asking the executor to pick a thread in its * pool. The Runnable will be renamed */ private void startupProcessor() { Processor processor = processorRef.get(); if (processor == null) { processor = new Processor(); if (processorRef.compareAndSet(null, processor)) { executor.execute(new NamePreservingRunnable(processor, threadName)); } } // Just stop the select() and start it again, so that the processor // can be activated immediately. wakeup(); }Session先被加入到队列中,然后IOProcessor启动了一个新的线程(Processor)来处理队列中Session的IO请求。在收到读的请求之后,Processor会触发IOFilterChain来处理读到的数据。IOFilterChain按拦截器模式设计,支持扩展。而mina框架本身提供了一个ExecutorFilter来支持在应用层实现多线程处理。这样就避免了应用层的阻塞妨碍到IO的读写。
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); } } protected void fireEvent(IoFilterEvent event) { executor.execute(event); }注意在这里会首先检查当前的事件是否已被用户指定,只有已指定的事件才会并发处理。所以并法控制需要用户谨慎地选择。当然用户也可以实现自己的并发策略,类似之前的IO处理线程,将同一个session的数据绑定到一个线程。
由此看来,mina对多线程的控制是非常精细的,尤其是IO处理线程与连接监听线程的分离,设计相当巧妙,值得学习。
- 源码研读-mina多线程模型
- 源码研读-netty多线程模型
- Bundler源码研读笔记
- Webx源码研读心得
- java源码研读快捷键
- EventBus源码研读(上)
- EventBus源码研读(中)
- EventBus源码研读(上)
- EventBus源码研读(中)
- EventBus源码研读(下)
- EventBus源码研读(上)
- EventBus源码研读(上)
- EventBus源码研读(中)
- EventBus源码研读(下)
- EventBus源码研读
- iOS MJRefresh源码研读
- Tomcat8.0.0源码研读
- Spring源码研读
- 广播,组播和多播的区别
- 自己动手写类似酷狗播放器(4)_系统托盘的显示
- uva 502 DEL command(字符串处理)
- javascript 数据类型转换
- 负载均衡实战记录
- 源码研读-mina多线程模型
- (Ext基础篇) Ext核心组件
- [Cocoa]多线程 NSThread
- [leetcode] Jump Game
- linux mmap 详解
- 技术人员谈管理之项目群的核心特征
- iOS页面传值(代理,属性,单例)-传值
- 如何在真机上调试Android应用程序(图文详解)
- 整理心情——生活资源