為了表示我不是標(biāo)題黨,先來個截圖:

Netty是Java世界里網(wǎng)絡(luò)編程框架的明星,也是我非常喜歡和推崇的開源項目之一。但其核心的Future接口實現(xiàn)卻犯了一個基本的邏輯錯誤,本文就指出了Netty中的核心Future接口在實現(xiàn)cancel和isDone方法時違反了約定規(guī)則的問題。
首先來看java.util.concurrent.Future#cancel方法的javadoc約定:
After this method returns, subsequent calls to isDone will always return true.
就是說,在調(diào)用了cancel方法后,再調(diào)用isDone將永遠(yuǎn)返回true。
Netty的Future接口繼承了Java的Future接口:
public interface Future<V> extends java.util.concurrent.Future<V>
所以在實現(xiàn)的時候理應(yīng)遵循這一約定,但Netty截止到目前的最新版本中(4.1.21),并沒有遵循這一約定,參見下面的代碼例子:
import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.concurrent.Promise;
public class DefaultPromiseIsDoneTest {
private final Promise defaultPromise = GlobalEventExecutor.INSTANCE.newPromise();
public static void main(String args[]) {
DefaultPromiseIsDoneTest main = new DefaultPromiseIsDoneTest();
main.isDoneTest();
}
private void isDoneTest() {
defaultPromise.setUncancellable();
defaultPromise.cancel(false);
boolean isDone = defaultPromise.isDone();
System.out.println(isDone);
}
}
運行后,控制臺打印的是 false。 而按照約定,應(yīng)該打印true才對。
Netty其它幾個實現(xiàn)類也沒有遵循這一約定:
io.netty.channel.group.VoidChannelGroupFuture#isDone
io.netty.channel.VoidChannelPromise#isDone
我在Netty的github上提出了這個問題,得到了Netty官方的確認(rèn)。
https://github.com/netty/netty/issues/7712
但由于修改會導(dǎo)致當(dāng)前版本用戶受到影響,所以Netty準(zhǔn)備在下一個大版本中修復(fù)這一問題。
我們在異步編程,實現(xiàn)Future接口的時候,對cancel和isDone方法的理解很可能會依賴于直覺,而沒有嚴(yán)格對照接口文檔中約定的邏輯來實現(xiàn)。甚至像Netty這樣的老司機也犯了大意的錯誤。特寫出這篇文章,跟大家共勉。
具體的討論可以參見我的stackoverflow帖子(本文開頭的圖片就截自下面的帖子):