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