先了解下future是个什么东东?
以 上三篇可以让你明白什么是future。
现在再来看mina中的iofuture
我 们常常发现有些东西只有一部分是公共的,其他部分是个性的,于是我们把公共的东西单独抽象成一个超接口(比如这里的IoFuture),其他个性的东 西,是在公共的基础上增加个性的东西,所以public interface ConnectFuture extends IoFuture;public interface ReadFuture extends IoFuture等等;同时,我们公共的东西可以公共的实现public class DefaultIoFuture implents IoFuture。然后个性的东西,在公共实现的基础上完成(重用:可以选择继承,或组合),于是public class ConnetFuture extends DefaultIoFuture implents ConnectFuture,其中extends DefaultIoFuture体现了用继承的方式重用公共的操作,implments ConnectFuture体现了在公共的基础上再去实现个性的东西。
如果要看Future机制的话,我们只需要了解DefaultIoFuture这个公共操作类。我们首先看下IoFuture描述了哪些功能需求:
(1)boolean isReady 判断“真实东西”是否准备完毕;
(2)await/awaitUninterruptibly 表示如果客户比较着急(可能在真实东西准备好之前就想提货),程序会阻塞客户,这里相对我前面的future pattern 中提供的措施要丰富 些,用户可以 选择长期阻塞await【内部最终实现是lock.wait()】,或者在一定时间内阻塞await(long timeout)【内部最终实现是lock.wait(timeout)】;
(3)addListener/removeListerner 这个东西和Future模式没有什么关系,只是个观察者模式。
(4)future pattern 中 说了还需要回答一个问题是: 当真实的数据准备好的时候,真实数据怎么通知这个Future说数据好了,在DefaultIoFuture中有一个protected void setValue(object newVaule)方法,以供提供真实数据的人调用。(这里顺便提下刚才的addListener/removeListener:当Future对应的 真实数据准备好时,方法setValue会被调用,那么Future接收到这个通知真实数据OK时,利用观察者模式把这个消息再向它的观察着进行广播 下。)
对future有了理解,再来阅读mina的源码就相当简单明了。
在mina中有两段重点注意下的代码,值得学习。
DefaultIoFuture中:
一是等待代码
/**
* 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;
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;
} else {
if (endTime < System.currentTimeMillis()) {
return ready;
}
}
}
} finally {
waiters--;
if (!ready) {
checkDeadLock();
}
}
}
}
二是检查死锁
/**
*
* TODO checkDeadLock.
*
*/
private void checkDeadLock() {
// Only read / write / connect / write future can cause dead lock.
if (!(this instanceof CloseFuture || this instanceof WriteFuture ||
this instanceof ReadFuture || this instanceof ConnectFuture)) {
return;
}
// Get the current thread stackTrace.
// Using Thread.currentThread().getStackTrace() is the best solution,
// even if slightly less efficient than doing a new Exception().getStackTrace(),
// as internally, it does exactly the same thing. The advantage of using
// this solution is that we may benefit some improvement with some
// future versions of Java.
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
// Simple and quick check.
for (StackTraceElement s: stackTrace) {
if (AbstractPollingIoProcessor.class.getName().equals(s.getClassName())) {
IllegalStateException e = new IllegalStateException( "t" );
e.getStackTrace();
throw new IllegalStateException(
"DEAD LOCK: " + IoFuture.class.getSimpleName() +
".await() was invoked from an I/O processor thread. " +
"Please use " + IoFutureListener.class.getSimpleName() +
" or configure a proper thread model alternatively.");
}
}
// And then more precisely.
for (StackTraceElement s: stackTrace) {
try {
Class<?> cls = DefaultIoFuture.class.getClassLoader().loadClass(s.getClassName());
if (IoProcessor.class.isAssignableFrom(cls)) {
throw new IllegalStateException(
"DEAD LOCK: " + IoFuture.class.getSimpleName() +
".await() was invoked from an I/O processor thread. " +
"Please use " + IoFutureListener.class.getSimpleName() +
" or configure a proper thread model alternatively.");
}
} catch (Exception cnfe) {
// Ignore
}
}
}