1.Future模式是一种常见的多线程设计模式,用来实现'异步'.其模式的核心在于去除main中的等待时间并使得原本需要等待的时间段可以用于处理其他的业务逻辑,从而充分利用计算机资源.
2.调用方式example:
ConnectFuture future = connector.connect(new InetSocketAddress("127.0.0.1", port));
future.awaitUninterruptibly();
session = future.getSession();
3.相关类图
4.源码_IoFuture
* 表示一个异步io操作的completion.
* 可通过IoFutureListener监听completion
*/
public interface IoFuture {
/** *//**
* 返回该future关联的session
*/
IoSession getSession();
/** *//**
* 等待异步操作完成
* 关联的listener将被通知完成
*/
IoFuture await() throws InterruptedException;
/** *//**
* 等待异步操作完成并指定超时时间
*
* @return <tt>true</tt> if the operation is completed.
*/
boolean await(long timeout, TimeUnit unit) throws InterruptedException;
/** *//**
* 等待异步操作完成并指定超时时间(毫秒)
*
* @return <tt>true</tt> if the operation is completed.
*/
boolean await(long timeoutMillis) throws InterruptedException;
/** *//**
* 等待异步操作完成且不可中断
* 关联的listener将被通知完成
*
* @return the current IoFuture
*/
IoFuture awaitUninterruptibly();
/** *//**
* 等待异步操作完成并指定超时时间
* 不可中断
*
* @return <tt>true</tt> if the operation is completed.
*/
boolean awaitUninterruptibly(long timeout, TimeUnit unit);
/** *//**
* 等待异步操作完成并指定超时时间(毫秒)
* 不可中断
*
* @return <tt>true</tt> if the operation is finished.
*/
boolean awaitUninterruptibly(long timeoutMillis);
/** *//**
* 已废弃. 替换方法为 {@link #awaitUninterruptibly()}.
*/
@Deprecated
void join();
/** *//**
* 已废弃. 替换方法为 {@link #awaitUninterruptibly(long)}.
*/
@Deprecated
boolean join(long timeoutMillis);
/** *//**
* 判断异步操作是否完成
*/
boolean isDone();
/** *//**
* 添加一个监听Future事件完成的listener
*/
IoFuture addListener(IoFutureListener<?> listener);
/** *//**
* 移除一个已存在的FutureListener
*/
IoFuture removeListener(IoFutureListener<?> listener);
}
1.从源码看,其提供了三类await方法
1.await,一直等待至操作完成
2.await(long),在指定的超时时间范围内等待
3.awaitUninterruptibly,等待且不可中断
2.对外提供了FutureListener.
5.源码_DefaultIoFuture
1.其实现了接口IoFuture,并提供了默认实现.
2.其内部有一个lock:
private final Object lock;//该lock用于await方法
该lock在DefaultIoFuture构造的时候初始化为this.
public DefaultIoFuture(IoSession session) {
this.session = session;
this.lock = this;
}
3.await()方法实现
synchronized (lock) {
while (!ready) {
waiters++;
try {
// 等待notify
// 假定寻在死锁
// 循环检查潜在的死锁
lock.wait(DEAD_LOCK_CHECK_INTERVAL);
} finally {
waiters--;
if (!ready) {
checkDeadLock();
}
}
}
}
return this;
}
1.ready表示异步操作是否完成{@link isDone()}
synchronized (lock) {
return ready;
}
}
2.DEAD_LOCK_CHECK_INTERVAL为检查死锁的周期时间,为5000L,即5s.
3.waiters表示当前正在wait的的线程数目,如果大于0,则表示有线程正在阻塞在wait方法.所以可以用这个变量判断是否notifyAll.
4.checkDeadLock()为检查死锁的方法:
其核心思路是检查当前调用线程的StackTrace,如果此时调用await的线程是I/O processor thread,则表示死锁发生(详见死锁的发生条件),则抛出IllegalStateException.
5.整体代码逻辑是在异步操作未完成以前循环的wait(5000L)并在超时后检查死锁直到ready.
4.await0()方法实现
long endTime = System.currentTimeMillis() + timeoutMillis;
if (endTime < 0) {
endTime = Long.MAX_VALUE;
}
synchronized (lock) {
if (ready) {
return ready;
} else if (timeoutMillis <= 0) {
// 这里如果timeoutMillis小于等于0,则直接返回ready flag
return ready;
}
waiters++;
try {
// 用一个无限循环来实现awaitUninterruptibly
for (;;) {
try {
long timeOut = Math.min(timeoutMillis, DEAD_LOCK_CHECK_INTERVAL);
lock.wait(timeOut);
} catch (InterruptedException e) {
// 这里说明当前线程在wait的时候被中断了(调用了interrupt).如果可被中断则继续向上层抛出InterruptedException.否则catch住不做任何操作,继续执行 //interruptable为false的时候表示Uninterruptibly.
if (interruptable) {
// 可中断则直接向上层抛出异常,则整个方法调用就结束了.反之则会继续执行catch后代码
throw e;
}
}
if (ready) {
return true;
}
// 该判断主要用来判断超时
if (endTime < System.currentTimeMillis()) {
return ready;
}
}
} finally {
waiters--;
if (!ready) {
checkDeadLock();
}
}
}
}
1.该方法是内部的一个private方法.其中第一个参数指定超时时间,第二个参数指明在wait的时候是否可被中断.
2.await(long timeout, TimeUnit unit)/await(long timeoutMillis)/awaitUninterruptibly的实现最终都调用了await0.
3.整体代码的实现即用一个无限循环+捕捉中断异常来实现awaitUninterruptibly.用endTime来实现超时.
4.仍然进行了潜在死锁的检查.
另外有一个问题是每次wait的时间都是Math.min(timeoutMillis, DEAD_LOCK_CHECK_INTERVAL).如果timeoutMillis为6s,则实际wait的时间是5 + 5 = 10s.不知道作者的这个设计是什么.
5.await(long timeoutMillis)调用了await0(timeoutMillis, true)/awaitUninterruptibly()调用了await0(Long.MAX_VALUE, false).
5.setValue()方法实现
synchronized (lock) {
// 仅一次
if (ready) {
return;
}
// 设置操作结果
result = newValue;
// 操作完成
ready = true;
if (waiters > 0) {
// 唤醒await的线程
lock.notifyAll();
}
}
// 通知监听器操作完成
notifyListeners();
}
这个方法是设置异步操作的结果表示操作完成.
6.源码_IoFutureListener
* 泛型接口,监听异步io操作完成
*/
1 . public interface IoFutureListener < F extends IoFuture > extends EventListener {
/** *//**
* 自实现的一个CLOSE_LISTENER.用于操作完成执行关闭session
*/
static IoFutureListener<IoFuture> CLOSE = new IoFutureListener<IoFuture>() {
public void operationComplete(IoFuture future) {
future.getSession().close(true);
}
};
/** *//**
* 操作完成时的回调接口
*/
void operationComplete(F future);
}
1.DefaultIoFuture的源码中提供了添加/移除/通知的方法.不过有一个比较疑惑的地方是:其提供了一个firstListener和一个otherListeners,不知道为什么有这样的需求.
2.DefaultIoFuture#addListener中对是否ready做了判断.只要ready就会通知.也就是在操作已经完成的情况下添加一个监听器,则也会执行回调方法.
7.when i/o operation complete?
1.ConnectFuture
{@link TailFilter#sessionCreated},调用了future.setSession(session)->调用setValue.->表示异步connect完成.
2.CloseFuture
{@link DefaultIoFilterChain#fireSessionClosed},调用了session.getCloseFuture().setClosed()->表示异步关闭完成
3.WriteFuture
{@link DefaultIoFilterChain#fireMessageSent},调用了request.getFuture().setWritten()>表示异步写完成
4.ReadFuture
{@link TailFilter#messageReceived},如果isUseReadOperation{@link IoSessionConfig},则执行setRead(Object message)->表示异步读完成.
8.总结
本篇介绍了mina内部异步的实现方式Future.着重介绍了await/awaitUninterruptly的实现方法等.