Apache Mina 源码再读6 Executor


Do I need to make my IoHandler thread-safe?


It depends on your implementation. If you access the resource which is shared across multiple sessions, you have to make it thread-safe. If the resource is not shared at all and accessed by only one session (e.g. storing context information as a session attribute), then you don't need to make it thread-safe.

 It is because all events generated by MINA are transmitted to your handler in order (when using the Executor Filter), and the newer event is not processed if the event handler method for the older event for the same session hasn't returned yet.


自定义IoHandler  需要线程安全吗?

主要依赖实现。如果在多个线程之间共享访问资源,那么需要线程安全。 如果,资源不共享,并且只有一个线程访问,那么就不需要线程安全。例如:在IoSession 存储信息。

因为,Apache  mina 产生的所有事件都是按照顺序被传输到IoHandler中,所以IoHandler 按照顺序来处理事件.如果同一个IoSession的方法不返回,那么后面的事件将不会处理。


public class ExecutorFilter  extends IoFilterAdapter{}


A filter that forwards I/O events to Executor to enforce a certain thread model while allowing the events per session to be processed simultaneously. You can apply various thread model by inserting this filter to a IoFilterChain.


ExecutorFilter 是一个IoFilterAdapter 过滤器。 ExecutorFilter 过滤器把I/O event  事件发送到executor接口中,并且强制设置一个线程模型。允许每一个IoSession中的事件被不断的处理。在ExecutorFilter中可以应用多种线程模型。


Event Ordering

All convenience constructors of this filter creates a new  OrderedThreadPoolExecutor  instance. Therefore, the order of event is maintained like the following:
  • All event handler methods are called exclusively. (e.g. messageReceived and messageSent can't be invoked at the same time.)
  • The event order is never mixed up. (e.g. messageReceived is always invoked before sessionClosed or messageSent.)
However, if you specified other  Executor  instance in the constructor, the order of events are not maintained at all. This means more than one event handler methods can be invoked at the same time with mixed order. For example, let's assume that messageReceived, messageSent, and sessionClosed events are fired.
  • All event handler methods can be called simultaneously. (e.g. messageReceived and messageSent can be invoked at the same time.)
  • The event order can be mixed up. (e.g. sessionClosed or messageSent can be invoked before messageReceived is invoked.)
If you need to maintain the order of events per session, please specify an  OrderedThreadPoolExecutor  instance or use the convenience constructors.




public class ExecutorFilter extends IoFilterAdapter {
    /** The list of handled events */
    private EnumSet<IoEventType> eventTypes;


    /** The associated executor */
    private Executor executor;


    /** A flag set if the executor can be managed */
    private boolean manageableExecutor;


    /** The default pool size */
    private static final int DEFAULT_MAX_POOL_SIZE = 16;


    /** The number of thread to create at startup */
    private static final int BASE_THREAD_NUMBER = 0;


    /** The default KeepAlive time, in seconds */
    private static final long DEFAULT_KEEPALIVE_TIME = 30;


    /** 
     * A set of flags used to tell if the Executor has been created 
     * in the constructor or passed as an argument. In the second case, 
     * the executor state can be managed.
     **/
    private static final boolean MANAGEABLE_EXECUTOR = true;


    private static final boolean NOT_MANAGEABLE_EXECUTOR = false;


    /** A list of default EventTypes to be handled by the executor */
    private static IoEventType[] DEFAULT_EVENT_SET = new IoEventType[] { IoEventType.EXCEPTION_CAUGHT,
            IoEventType.MESSAGE_RECEIVED, IoEventType.MESSAGE_SENT, IoEventType.SESSION_CLOSED,
            IoEventType.SESSION_IDLE, IoEventType.SESSION_OPENED };


    /**
     * (Convenience constructor) Creates a new instance with a new
     * {@link OrderedThreadPoolExecutor}, no thread in the pool, and a 
     * maximum of 16 threads in the pool. All the event will be handled 
     * by this default executor.
     */
    public ExecutorFilter() {
        // Create a new default Executor
        Executor executor = createDefaultExecutor(BASE_THREAD_NUMBER, DEFAULT_MAX_POOL_SIZE, DEFAULT_KEEPALIVE_TIME,
                TimeUnit.SECONDS, Executors.defaultThreadFactory(), null);


        // Initialize the filter
        init(executor, MANAGEABLE_EXECUTOR);
    }


 private Executor createDefaultExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
            ThreadFactory threadFactory, IoEventQueueHandler queueHandler) {
        // Create a new Executor
        Executor executor = new OrderedThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit,
                threadFactory, queueHandler);


        return executor;
    }


  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、 ExcutorFilter  继承了IoHandlerAdaptor  来处理Apache  Mina 的I/O 操作事件。


 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);
        }
    }


当messageReceived()事件触发时,创建一个IoFilterEvent 任务,并提交到Excutor接口中等待处理。

而ExcutorFilter  中的excutor 接口默认为OrderedThreadPoolExecutor 有序线程池。


   /**
     * Fires the specified event through the underlying executor.
     * 
     * @param event The filtered event
     */
    protected void fireEvent(IoFilterEvent event) {
        executor.execute(event);
    }



public class OrderedThreadPoolExecutor extends ThreadPoolExecutor { }


在JDK线程池中提供了基础的缓存线程池,以及基于缓存的具有调度的线程池,Apache Mina 中提供了OrderedThreadPoolExecutor 线程池,这个线程池保证了每一个IoSession中接收到的消息会被按照顺序处理。


OrderedThreadPoolExecutor  顺序线程池基于JDK的ThreadPoolExecutor 。


当IoEventFilter 提交到ThreadPoolExecutor.


    @Override
    public void execute(Runnable task) {
        if (shutdown) {
            rejectTask(task);
        }

        // Check that it's a IoEvent task
        checkTaskType(task);

        IoEvent event = (IoEvent) task;

        // Get the associated session
        IoSession session = event.getSession();

        // Get the session's queue of events
        SessionTasksQueue sessionTasksQueue = getSessionTasksQueue(session);
        Queue<Runnable> tasksQueue = sessionTasksQueue.tasksQueue;

        boolean offerSession;

        // propose the new event to the event queue handler. If we
        // use a throttle queue handler, the message may be rejected
        // if the maximum size has been reached.
        boolean offerEvent = eventQueueHandler.accept(this, event);

        if (offerEvent) {
            // Ok, the message has been accepted
            synchronized (tasksQueue) {
                // Inject the event into the executor taskQueue
                tasksQueue.offer(event);

                if (sessionTasksQueue.processingCompleted) {
                    sessionTasksQueue.processingCompleted = false;
                    offerSession = true;
                } else {
                    offerSession = false;
                }

                if (LOGGER.isDebugEnabled()) {
                    print(tasksQueue, event);
                }
            }
        } else {
            offerSession = false;
        }

        if (offerSession) {
            // As the tasksQueue was empty, the task has been executed
            // immediately, so we can move the session to the queue
            // of sessions waiting for completion.
            waitingSessions.offer(session);
        }

        addWorkerIfNecessary();

        if (offerEvent) {
            eventQueueHandler.offered(this, event);
        }
    }



1、 首先获取与IoSession相关的tasksQueue 任务队列。


 /**
     * Get the session's tasks queue.
     */
    private SessionTasksQueue getSessionTasksQueue(IoSession session) {
        SessionTasksQueue queue = (SessionTasksQueue) session.getAttribute(TASKS_QUEUE);


        if (queue == null) {
            queue = new SessionTasksQueue();
            SessionTasksQueue oldQueue = (SessionTasksQueue) session.setAttributeIfAbsent(TASKS_QUEUE, queue);


            if (oldQueue != null) {
                queue = oldQueue;
            }
        }


        return queue;
    }


2、


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值