一個讓Netty作者也感到驚訝的錯誤

來自專欄 Java5 人贊了文章

為了表示我不是標題黨,先來個截圖:

Netty是Java世界裡網路編程框架的明星,也是我非常喜歡和推崇的開源項目之一。但其核心的Future介面實現卻犯了一個基本的邏輯錯誤,本文就指出了Netty中的核心Future介面在實現cancel和isDone方法時違反了約定規則的問題。

首先來看java.util.concurrent.Future#cancel方法的javadoc約定:

After this method returns, subsequent calls to isDone will always return true.

就是說,在調用了cancel方法後,再調用isDone將永遠返回true。

Netty的Future介面繼承了Java的Future介面:

public interface Future<V> extends java.util.concurrent.Future<V>

所以在實現的時候理應遵循這一約定,但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。 而按照約定,應該列印true才對。

Netty其它幾個實現類也沒有遵循這一約定:

io.netty.channel.group.VoidChannelGroupFuture#isDoneio.netty.channel.VoidChannelPromise#isDone

我在Netty的github上提出了這個問題,得到了Netty官方的確認。

github.com/netty/netty/

但由於修改會導致當前版本用戶受到影響,所以Netty準備在下一個大版本中修復這一問題。

我們在非同步編程,實現Future介面的時候,對cancel和isDone方法的理解很可能會依賴於直覺,而沒有嚴格對照介面文檔中約定的邏輯來實現。甚至像Netty這樣的老司機也犯了大意的錯誤。特寫出這篇文章,跟大家共勉。

具體的討論可以參見我的stackoverflow帖子(本文開頭的圖片就截自下面的帖子):

does-netty-violate-the-contract-of-future-cancel-method

推薦閱讀:

相关文章