Apache Mina 源碼再讀 1 Bind過程以及DefaultIoFuture源碼

1 、bind 事件  

在服務器端調用public final void bind(SocketAddress... addresses) throws IOException 方法綁定本地端口時,

仔細看看,Apache Mina 在bind()本地端口做了哪些事情?


 protected final Set<SocketAddress> bindInternal(List<? extends SocketAddress> localAddresses) throws Exception {
        // Create a bind request as a Future operation. When the selector
        // have handled the registration, it will signal this future.
        AcceptorOperationFuture request = new AcceptorOperationFuture(localAddresses);

        // adds the Registration request to the queue for the Workers
        // to handle
        registerQueue.add(request);

        // creates the Acceptor instance and has the local
        // executor kick it off.
        startupAcceptor();

        // As we just started the acceptor, we have to unblock the select()
        // in order to process the bind request we just have added to the
        // registerQueue.
        try {
            lock.acquire();

            // Wait a bit to give a chance to the Acceptor thread to do the select()
            Thread.sleep(10);
            wakeup();
        } finally {
            lock.release();
        }

        // Now, we wait until this request is completed.
        request.awaitUninterruptibly();

        if (request.getException() != null) {
            throw request.getException();
        }

        // Update the local addresses.
        // setLocalAddresses() shouldn't be called from the worker thread
        // because of deadlock.
        Set<SocketAddress> newLocalAddresses = new HashSet<SocketAddress>();

        for (H handle : boundHandles.values()) {
            newLocalAddresses.add(localAddress(handle));
        }

        return newLocalAddresses;
    }


創建一個Bind事情請求,這事情請求是Future 操作。異步操作。然後select循環會處理這個bind事情,然後通知結果。


AcceptorOperationFuture 是一個異步Future操作. AcceptorOperationFuture 繼承了DefaultIoFuture 類。這是一個Apache Mina 對於Future操作的內部實現。

org.apache.mina.core.future 包裏面有多種Future操作。

其中包括:

1、 CloseFuture 

2、ConnectFuture 

3、ReadFuture   

4、WriteFuture 

以及這些Future的默認實現。 同時,對這些異步操作,future包中也定義了對應的事件監聽器。IoFutureListener ,當Future操作完成時,觸發IoFutureListener監聽器。



/**
 * Something interested in being notified when the completion
 * of an asynchronous I/O operation : {@link IoFuture}. 
 *
 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
 */
public interface IoFutureListener<F extends IoFuture> extends EventListener {
    /**
     * An {@link IoFutureListener} that closes the {@link IoSession} which is
     * associated with the specified {@link IoFuture}.
     */
    static IoFutureListener<IoFuture> CLOSE = new IoFutureListener<IoFuture>() {
        public void operationComplete(IoFuture future) {
            future.getSession().close(true);
        }
    };

    /**
     * Invoked when the operation associated with the {@link IoFuture}
     * has been completed even if you add the listener after the completion.
     *
     * @param future  The source {@link IoFuture} which called this
     *                callback.
     */
    void operationComplete(F future);
}

       // Create a bind request as a Future operation. When the selector
        // have handled the registration, it will signal this future.
        AcceptorOperationFuture request = new AcceptorOperationFuture(localAddresses);


通過以上代碼,創建了一個Future 異步操作。然後,把Future保存到隊列中,然select 異步來操作完成AcceptorOperation的事件.


        // adds the Registration request to the queue for the Workers
        // to handle
        registerQueue.add(request);


    private final Queue<AcceptorOperationFuture> registerQueue = new ConcurrentLinkedQueue<AcceptorOperationFuture>();


    // creates the Acceptor instance and has the local
        // executor kick it off.
        startupAcceptor();

然後通過startAcceptor()方法來啓動一個Acceptor 線程。



        // As we just started the acceptor, we have to unblock the select()
        // in order to process the bind request we just have added to the
        // registerQueue.
        try {
            lock.acquire();


            // Wait a bit to give a chance to the Acceptor thread to do the select()
            Thread.sleep(10);
            wakeup();
        } finally {
            lock.release();
        }


然後通過lock信號量,通過當前線程Thread.sleep(10),來讓另外一個線程來完成AcceptorOperation操作。


 // Now, we wait until this request is completed.
        request.awaitUninterruptibly();

最後一直等到AcceptorOperationFuture異步操作的完成。 這個是異步轉換成同步的方式。


異步轉換同步,可以通過object.await() 、object.notifyAll()來實現。這個主要看DefaultIoFuture 源代碼。



在Acceptor 線程中有一個registerHandles()方法時專門來處理AcceptorOperationFuture 操作。


    private int registerHandles() 
    {
        for (;;) 
        {
            // The register queue contains the list of services to manage
            // in this acceptor.
            AcceptorOperationFuture future = registerQueue.poll();

            if (future == null)
            {
                return 0;
            }

            // We create a temporary map to store the bound handles,
            // as we may have to remove them all if there is an exception
            // during the sockets opening.
            Map<SocketAddress, H> newHandles = new ConcurrentHashMap<SocketAddress, H>();
            List<SocketAddress> localAddresses = future.getLocalAddresses();

            try 
            {
                // Process all the addresses
                for (SocketAddress a : localAddresses)
                {
                    H handle = open(a);
                    newHandles.put(localAddress(handle), handle);
                }

                // Everything went ok, we can now update the map storing
                // all the bound sockets.
                boundHandles.putAll(newHandles);

                // and notify.
                future.setDone();
                return newHandles.size();
                
                ///////////////以上代碼判斷新鏈接的socket數量///////////////////////
            } catch (Exception e) {
                // We store the exception in the future
                future.setException(e);
            } finally {
                // Roll back if failed to bind all addresses.
                if (future.getException() != null) {
                    for (H handle : newHandles.values()) {
                        try {
                            close(handle);
                        } catch (Exception e) {
                            ExceptionMonitor.getInstance().exceptionCaught(e);
                        }
                    }

                    // TODO : add some comment : what is the wakeup() waking up ?
                    wakeup();
                }
            }
        }
    }

registerHandles()方法來迭代registerQueue 隊列。 registerQueue隊列是線程安全的。registerQueue隊列被調用bind()線程和Acceptor線程共同訪問。


當Accept事件完成時,會調用Future.setDone()來通知bind()線程停止等待。



在這個階段中DefaultIoFuture 類實現了類似JDK  Future 模型。 我們重點學習一下DefaultIoFuture 類的功能。



2、DefaultIoFuture源碼剖析


/**
 * Represents the completion of an asynchronous I/O operation on an 
 * {@link IoSession}.
 * Can be listened for completion using a {@link IoFutureListener}.
 * 
 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
 */
public interface IoFuture {
    /**
     * Returns the {@link IoSession} which is associated with this future.
     */
    IoSession getSession();

    /**
     * Wait for the asynchronous operation to complete.
     * The attached listeners will be notified when the operation is 
     * completed.
     */
    IoFuture await() throws InterruptedException;

    /**
     * Wait for the asynchronous operation to complete with the specified timeout.
     *
     * @return <tt>true</tt> if the operation is completed.
     */
    boolean await(long timeout, TimeUnit unit) throws InterruptedException;

    /**
     * Wait for the asynchronous operation to complete with the specified timeout.
     *
     * @return <tt>true</tt> if the operation is completed.
     */
    boolean await(long timeoutMillis) throws InterruptedException;

    /**
     * Wait for the asynchronous operation to complete uninterruptibly.
     * The attached listeners will be notified when the operation is 
     * completed.
     * 
     * @return the current IoFuture
     */
    IoFuture awaitUninterruptibly();

    /**
     * Wait for the asynchronous operation to complete with the specified timeout
     * uninterruptibly.
     *
     * @return <tt>true</tt> if the operation is completed.
     */
    boolean awaitUninterruptibly(long timeout, TimeUnit unit);

    /**
     * Wait for the asynchronous operation to complete with the specified timeout
     * uninterruptibly.
     *
     * @return <tt>true</tt> if the operation is finished.
     */
    boolean awaitUninterruptibly(long timeoutMillis);

    /**
     * @deprecated Replaced with {@link #awaitUninterruptibly()}.
     */
    @Deprecated
    void join();

    /**
     * @deprecated Replaced with {@link #awaitUninterruptibly(long)}.
     */
    @Deprecated
    boolean join(long timeoutMillis);

    /**
     * Returns if the asynchronous operation is completed.
     */
    boolean isDone();

    /**
     * Adds an event <tt>listener</tt> which is notified when
     * this future is completed. If the listener is added
     * after the completion, the listener is directly notified.
     */
    IoFuture addListener(IoFutureListener<?> listener);

    /**
     * Removes an existing event <tt>listener</tt> so it won't be notified when
     * the future is completed.
     */
    IoFuture removeListener(IoFutureListener<?> listener);
}


DefaultIoFuture  實現了IoFuture 接口。

IoFuture Represents the completion of an asynchronous I/O operation on an IoSession .

IoFuture接口表示異步Io操作的完成。同時提供addListener 、removeListener 監聽器的功能。當IoFuture 操作完成時,會調用IoFutureListener 的方法。



public interface IoFuture {
    /**
     * Returns the {@link IoSession} which is associated with this future.
     */
    IoSession getSession();

    /**
     * Wait for the asynchronous operation to complete.
     * The attached listeners will be notified when the operation is 
     * completed.
     */
    IoFuture await() throws InterruptedException;

    /**
     * Wait for the asynchronous operation to complete with the specified timeout.
     *
     * @return <tt>true</tt> if the operation is completed.
     */
    boolean await(long timeout, TimeUnit unit) throws InterruptedException;

    /**
     * Wait for the asynchronous operation to complete with the specified timeout.
     *
     * @return <tt>true</tt> if the operation is completed.
     */
    boolean await(long timeoutMillis) throws InterruptedException;

    /**
     * Wait for the asynchronous operation to complete uninterruptibly.
     * The attached listeners will be notified when the operation is 
     * completed.
     * 
     * @return the current IoFuture
     */
    IoFuture awaitUninterruptibly();

    /**
     * Wait for the asynchronous operation to complete with the specified timeout
     * uninterruptibly.
     *
     * @return <tt>true</tt> if the operation is completed.
     */
    boolean awaitUninterruptibly(long timeout, TimeUnit unit);

    /**
     * Wait for the asynchronous operation to complete with the specified timeout
     * uninterruptibly.
     *
     * @return <tt>true</tt> if the operation is finished.
     */
    boolean awaitUninterruptibly(long timeoutMillis);

    /**
     * @deprecated Replaced with {@link #awaitUninterruptibly()}.
     */
    @Deprecated
    void join();

    /**
     * @deprecated Replaced with {@link #awaitUninterruptibly(long)}.
     */
    @Deprecated
    boolean join(long timeoutMillis);

    /**
     * Returns if the asynchronous operation is completed.
     */
    boolean isDone();

    /**
     * Adds an event <tt>listener</tt> which is notified when
     * this future is completed. If the listener is added
     * after the completion, the listener is directly notified.
     */
    IoFuture addListener(IoFutureListener<?> listener);

    /**
     * Removes an existing event <tt>listener</tt> so it won't be notified when
     * the future is completed.
     */
    IoFuture removeListener(IoFutureListener<?> listener);
}



public class DefaultIoFuture implements IoFuture {


    /** A number of seconds to wait between two deadlock controls ( 5 seconds ) */
    private static final long DEAD_LOCK_CHECK_INTERVAL = 5000L;


    /** The associated session */
    private final IoSession session;
 
   
    /** A lock used by the wait() method */
    private final Object lock;


    private IoFutureListener<?> firstListener;


    private List<IoFutureListener<?>> otherListeners;

    //異步操作的結果
    private Object result;
    //異步操作是否完成
    private boolean ready;

   //當前等待異步操作的線程數量
    private int waiters;


    /**
     * Creates a new instance associated with an {@link IoSession}.
     *
     * @param session an {@link IoSession} which is associated with this future
     */
    public DefaultIoFuture(IoSession session) {
        this.session = session;
        this.lock = this;
    }



   //調用await0()方法,將會同步等待異步操作的完成。
    /**
     * Wait for the Future to be ready. If the requested delay is 0 or
     * negative, this method immediately returns the value of the
     * 'ready' flag.
     * Every 5 second, the wait will be suspended to be able to check if
     * there is a deadlock or not.
     * 
     * @param timeoutMillis The delay we will wait for the Future to be ready
     * @param interruptable Tells if the wait can be interrupted or not
     * @return <code>true</code> if the Future is ready
     * @throws InterruptedException If the thread has been interrupted
     * when it's not allowed.
     */
    private boolean await0(long timeoutMillis, boolean interruptable) throws InterruptedException {
        long endTime = System.currentTimeMillis() + timeoutMillis;


        if (endTime < 0) {
            endTime = Long.MAX_VALUE;
        }


        synchronized (lock) {
            if (ready) {
                return ready;
            } else if (timeoutMillis <= 0) {
                return ready;
            }


            waiters++;


            try {
                for (;;) {
                    try {
                        long timeOut = Math.min(timeoutMillis, DEAD_LOCK_CHECK_INTERVAL);
                        lock.wait(timeOut);
                    } catch (InterruptedException e) {
                        if (interruptable) {
                            throw e;
                        }
                    }


                    if (ready) {
                        return true;
                    }


                    if (endTime < System.currentTimeMillis()) {
                        return ready;
                    }
                }
            } finally {
                waiters--;
                if (!ready) {
                    checkDeadLock();
                }
            }
        }
    }


   //當IoFuture 事件完成時, 調用setValue() 設置IoFuture異步計算的結果,並通過notifyListeners()方法來完成監聽器的調用

    /**
     * Sets the result of the asynchronous operation, and mark it as finished.
     */
    public void setValue(Object newValue) {
        synchronized (lock) {
            // Allow only once.
            if (ready) {
                return;
            }


            result = newValue;
            ready = true;
            if (waiters > 0) {
                lock.notifyAll();
            }
        }


        notifyListeners();
    }


    public IoFuture addListener(IoFutureListener<?> listener) {
        if (listener == null) {
            throw new IllegalArgumentException("listener");
        }


        boolean notifyNow = false;
        synchronized (lock) {
            if (ready) {
                notifyNow = true;
            } else {
                if (firstListener == null) {
                    firstListener = listener;
                } else {
                    if (otherListeners == null) {
                        otherListeners = new ArrayList<IoFutureListener<?>>(1);
                    }
                    otherListeners.add(listener);
                }
            }
        }


        if (notifyNow) {
            notifyListener(listener);
        }
        return this;
    }


    /**
     * {@inheritDoc}
     */
    public IoFuture removeListener(IoFutureListener<?> listener) {
        if (listener == null) {
            throw new IllegalArgumentException("listener");
        }


        synchronized (lock) {
            if (!ready) {
                if (listener == firstListener) {
                    if (otherListeners != null && !otherListeners.isEmpty()) {
                        firstListener = otherListeners.remove(0);
                    } else {
                        firstListener = null;
                    }
                } else if (otherListeners != null) {
                    otherListeners.remove(listener);
                }
            }
        }


        return this;
    }


    private void notifyListeners() {
        // There won't be any visibility problem or concurrent modification
        // because 'ready' flag will be checked against both addListener and
        // removeListener calls.
        if (firstListener != null) {
            notifyListener(firstListener);
            firstListener = null;


            if (otherListeners != null) {
                for (IoFutureListener<?> l : otherListeners) {
                    notifyListener(l);
                }
                otherListeners = null;
            }
        }
    }

}










發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章