文章目录
问题
在使用异步编程的时候,Future模式实现需要注意几个问题:
- 当提前已经Complete,但是还没有设置Handler,这时候需要在设置Handler的时候执行Handler方法
- 当提前已经设置了Handler,在执行Complete方法的时候,需要执行Handler方法
解决
其实,只要在Complete方法里面判断当前有没有设置Handler,如果设置了,那就执行Handler,如果没有,就没有,然后在设置Handler方法里面判断当前有没有执行完成,如果执行完成,那就直接执行Handler,如果没有,就没有…当然,执行的时候要考虑线程安全问题,我们可以直接使用synchronized关键字来进行线程安全问题处理,因为在1.8之后性能也不是很低…
我们看vert.x里面的Future的具体实现
首先我们看Future的实现:
有个叫FutureImpl,应该就是具体的简单实现,当然,我们也可以直接实现,然后使用自己封装的Futrure去完成需求,当然,如果有一些定制的需求,建议直接继承FutureImpl,去重写对应方法好了…
线看一看属性:
比较简单,就是是否成功,失败,设置的Handler,结果和异常信息…
先看isComplete方法,
如果不使用两个属性,成功失败,会造成什么情况,默认都是false,我就不知道,到底是失败了还是没有执行…如果执行失败那么failed会是true,
再看setHandler方法
按照我们刚才说的,setHandler,只需要判断将当前handler设置进去,然后判断有没有执行成功,如果执行成功了,那就执行当前Handler,如果没有,就不管:
/**
* Set a handler for the result. It will get called when it's complete
*/
public Future<T> setHandler(Handler<AsyncResult<T>> handler) {
boolean callHandler;
//防止线程安全问题...
synchronized (this) {
this.handler = handler;
// 可能会在此刻,去执行setHandler方法
callHandler = isComplete();
}
if (callHandler) {
handler.handle(this);
}
return this;
}
再看complete方法
就是tryComplete方法:我们完成只需要将结果赋值进去,然后判断当前Handler有没有设置,如果设置了,那就执行,如果没有设置那就直接返回.
源码如下:
@Override
public boolean tryComplete(T result) {
Handler<AsyncResult<T>> h;
//线程安全问题
synchronized (this) {
//如果已经执行完成,那就直接返回,并抛出异常
if (succeeded || failed) {
return false;
}
this.result = result;
succeeded = true;
// 可能会在此刻,去执行setHandler方法,下面还没有执行
h = handler;
}
if (h != null) {
h.handle(this);
}
return true;
}
如果.没有使用synchronized加锁,会造成什么问题?
在setHandler的时候,如果当设置完成Handler,线程切出去执行complete方法,这时候会执行两次Handler;
在complete的时候,如果刚把成功状态改为成功,还没有进行Handler的赋值的时候,去执行setHandler,这时候也会执行两次Handler,就会导致线程安全问题.