netty中的future继承自jdk中cocurrent包下future的接口。
Future的V可以是void,不一定是有返回值的,所以通过返回值来判断task isDone()是错误的。所以isDone的判断不应该通过返回值来做。只有isDone了之后,才去做get操作。所以get里面也会抛异常。
通过isDone来判断是否结束了。
正常的Future在jdk中的使用方法,Future针对的就是一个task,task往往是一个runnable,Future和runnable在一起,他就是一个task。
FutureTask
executor.execute(future);
把future放在execute里面,执行的是runnable对象,只不过是用Future管理了一下。Task里面需要设定状态,Future是针对要执行的任务的封装,对任务做了一个增强的操作。但是netty里面的future,这些方法是不够的。所以添加了一些接口,而且是异步的操作。
jdk里面的Future是isDone,没有判断是否成功,只判断了是否取消了(isCalled),netty里面的future是isSuccess,还加了是否可以取消。是对状态判断的补充。cause方法,抛出异常之后可以知道是怎样跑出的什么异常。netty的future,很核心的一个方法:addListener,通过isDone判断这个future结束了,结束了之后立马唤醒这个listener。相当于就是一个回调。
有增加一般就有删除,所以有removeListener。
future需要特别注意的方法有三个,isDone,isSuccess,addListener。
知道这个之后,再来说一下函数式编程,函数式编程会强调一个promise。就是成功之后会做什么事,失败之后会做什么事。promise和响应式编程很像,有onNext,onComplete,onError这几种处理,你有元素下发的时候怎么处理,当你正常结束的时候怎么处理,当出错的时候怎么处理。我们的正常使用只是一个地址的访问,给我返回结果,我们只需要对结果进行判断它是成功还是失败。如果只需要考虑这2种,使用promise就可以了。所以future又拓展了一个promise。
如何判断是isSuccess,promise提供了setSuccess,trySuccess,标记为success同时通知所有的listener。
promise接口继承自future,所以它重写了一些方法,把返回值有Future改为了Promise。以addListener为例,在函数式编程中,添加的是一个动作,操作的是Future,很明显是一个函数式接口,就是结束之后应该做什么,只不过标记了是EventListener。EventListener是一个标记,并没有设定方法。
在netty中是如何使用的,我们更多的是针对channel,可以以channel为例,来分析promise一些比较核心的用法。
首先有个接口,ChannelPromise,同样ChannelPromise返回的都是ChannelPromise,它继承ChannelFuture和Promise。
然后来看一下ChannelFuture的默认使用:DefaultChannelFuture
他继承自DefaultPromise,先看一下DefaultPromise:
先看addListener方法,addListener是一个动作,它需要做一些事情。
一个是添加进去,addListener0,添加进去肯定是要做管理的,那如何管理,要么是容器要么是链表。
那这个里面,DefaultFutureListener里面是一个容器,一个数组,只不过是限定了类型。
addListener做了2件事,一个是做添加,添加完之后,就要做判断这个task是否已经结束了。jdk中的Future的一个核心方法之一就是isDone().人物的结束与否并不是看你是否返回了结果,而是看isDone,所以在做任何事之前,先判断是否isDone。假如结束之后就notifyListeners(),之所以说addListener它是一个回调,是因为notifyListeners可以拿到一个executer,然后做事情。
对listener进行遍历,然后执行。我们管理了一个针对Future的动作。
监听器就是一个回调,只不过做了相应的封装。
所以在添加listener的时候,一定要注意有一个isDone的判断。
看一下DefaultPromise的isDone():
假如我们并没有设置值的话,result就是null,他只不过传入了一个Object。它并没有限定类型,可以放DefaultPromise的V类型,同样也可以只是一个Object,管理几种装态,这个isDone只是代表结束了,并不是代表成功了。
isDone之后,需要做isSuccess的判断。那isSuccess应该放在哪一块去做呢?
还是看DefaultPromise:
默认情况下它是成功或者有值的。
然后来看一下DefaultChannelFuture的setSuccess方法:
setSuccess为null,然后trySuccess也是null。
如果你传的是null,就设置为SUCCESS.设置完之后就是一个通知的回调。
然后看一下他们常见的调用:
设置为success状态之后返回,在使用的时候只需要点addListener即可,就直接去执行listener中的动作了。
pool.acquire()已经把success设置进去了,所以只需要addListener即可。他的isDone就结束了。所以addLIstener就直接去执行相关的代码了。
同样的,获取连接也是先去判断是否isDone,结束了的话,就做结束之后的动作,
首先我自己定义了一个promise,你拿到这个channel,放到这个promise里面,外层的话,就可以做到一个控制。在这一块儿,直接加一个listener就行了。用的就是netty的一贯的套路。
在使用future的使用,通过这种方式,我们学会使用addListener,我们要指导addListener要经过哪些操作,第一步添加,第二步,通过isDone判断是否结束了,结束了的话,就做一些事,isDone后面紧跟的就是isSuccess,我是不是成功设定了,成功了的话,我才会去取。假如失败的话,就tryFuture,如果有异常的话,就future.cause().
接着我们在看一下其他的代码,
config().group().register(channel)得到一个ChannelFuture,如果要判断isDone,再判断isSuccess,不如直接判断cause()是否为null,不为null,再判断是否注册了,没有注册成功的话,就close,没有异常直接返回去,不会做任何其他的动作。
学过nio的就应该知道,注册其实还是要通过channel.register()来实现。
它通过ChannelPromise把Channel包裹进来,然后它就可以拿到当前的selector,
所以可以把promise看成一个针对channel的动作。