ChannelFuture的用法

該文章基于個(gè)人的理解,翻譯自netty5.0 API。

綜述

ChannelFuture的作用是用來(lái)保存Channel異步操作的結(jié)果。

我們知道,在Netty中所有的I/O操作都是異步的。這意味著任何的I/O調(diào)用都將立即返回,而不保證這些被請(qǐng)求的I/O操作在調(diào)用結(jié)束的時(shí)候已經(jīng)完成。取而代之地,你會(huì)得到一個(gè)返回的ChannelFuture實(shí)例,這個(gè)實(shí)例將給你一些關(guān)于I/O操作結(jié)果或者狀態(tài)的信息。

對(duì)于一個(gè)ChannelFuture可能已經(jīng)完成,也可能未完成。當(dāng)一個(gè)I/O操作開(kāi)始的時(shí)候,一個(gè)新的future對(duì)象就會(huì)被創(chuàng)建。在開(kāi)始的時(shí)候,新的future是未完成的狀態(tài)--它既非成功、失敗,也非被取消,因?yàn)镮/O操作還沒(méi)有結(jié)束。如果I/O操作以成功、失敗或者被取消中的任何一種狀態(tài)結(jié)束了,那么這個(gè)future將會(huì)被標(biāo)記為已完成,并包含更多詳細(xì)的信息(例如:失敗的原因)。請(qǐng)注意,即使是失敗被取消的狀態(tài),也是屬于已完成的狀態(tài)。

下面這張圖來(lái)自于官方文檔,用于說(shuō)明各種狀態(tài)的關(guān)系:

ChannelFuture狀態(tài)關(guān)系

各種各樣的方法被提供,用來(lái)檢查I/O操作是否已完成、等待完成,并尋回I/O操作的結(jié)果。它同樣允許你添加ChannelFutureListener,以便于在I/O操作完成的時(shí)候,你能夠獲得通知。

優(yōu)先使用addListener(GenericFutureListener),而非await()

當(dāng)做了一個(gè)I/O操作并有任何后續(xù)任務(wù)的時(shí)候,推薦優(yōu)先使用addListener(GenericFutureListener)的方式來(lái)獲得通知,而非await()。

addListener(GenericFutureListener)是非阻塞的。它會(huì)把特定的ChannelFutureListener添加到ChannelFuture中,然后I/O線(xiàn)程會(huì)在I/O操作相關(guān)的future完成的時(shí)候通知監(jiān)聽(tīng)器。ChannelFutureListener會(huì)利于最佳的性能和資源的利用,因?yàn)樗稽c(diǎn)阻塞都沒(méi)有。然而,如果你不使用基于事件驅(qū)動(dòng)的編程方式,去實(shí)現(xiàn)一個(gè)后續(xù)式的邏輯會(huì)變得詭異和難于理解。

對(duì)比來(lái)看,await()是一個(gè)阻塞的操作。一旦被調(diào)用,調(diào)用者線(xiàn)程會(huì)阻塞,直到操作完成。使用await()來(lái)實(shí)現(xiàn)一個(gè)后續(xù)式的邏輯會(huì)更容易,但是調(diào)用者線(xiàn)程會(huì)非常沒(méi)必要的阻塞直到I/O操作完成,并且內(nèi)部的線(xiàn)程通知是相對(duì)來(lái)說(shuō)代價(jià)昂貴的。更有甚者,在一些特定的情況下會(huì)產(chǎn)生死鎖,下面是對(duì)這種情況的描述:

 // BAD - NEVER DO THIS
 @Override
 public void channelRead(ChannelHandlerContext ctx, GoodByeMessage msg) {
     ChannelFuture future = ctx.channel().close();
     future.awaitUninterruptibly();
     // Perform post-closure operation
     // ...
 }

 // GOOD
 @Override
 public void channelRead(ChannelHandlerContext ctx,  GoodByeMessage msg) {
     ChannelFuture future = ctx.channel().close();
     future.addListener(new ChannelFutureListener() {
         public void operationComplete(ChannelFuture future) {
             // Perform post-closure operation
             // ...
         }
     });
 }

撇開(kāi)上面提到的缺點(diǎn)不談,確實(shí)還是有一些情況在調(diào)用await()的時(shí)候會(huì)更方便的。在這種情況下,請(qǐng)確保你不是在一個(gè)I/O線(xiàn)程中調(diào)用的await()。否則,為了避免死鎖的情況,BlockingOperationException將被提出。

不要混淆I/O timeout和await timeout

你在使用Future.await(long), Future.await(long, TimeUnit),F(xiàn)uture.awaitUninterruptibly(long),或者Future.awaitUninterruptibly(long, TimeUnit)的時(shí)候,指定的timeout的值和I/O timeout一點(diǎn)關(guān)系都沒(méi)有。如果一個(gè)操作超時(shí)了,future將會(huì)被標(biāo)記為已完成-失敗,就像上面的圖中描述的那樣。例如,連接超時(shí)應(yīng)當(dāng)通過(guò)一個(gè)傳輸特定的選項(xiàng)來(lái)配置:

 // BAD - NEVER DO THIS
 Bootstrap b = ...;
 ChannelFuture f = b.connect(...);
 f.awaitUninterruptibly(10, TimeUnit.SECONDS);
 if (f.isCancelled()) {
     // Connection attempt cancelled by user
 } else if (!f.isSuccess()) {
     // You might get a NullPointerException here because the future
     // might not be completed yet.
     f.cause().printStackTrace();
 } else {
     // Connection established successfully
 }

 // GOOD
 Bootstrap b = ...;
 // Configure the connect timeout option.
 b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000);
 ChannelFuture f = b.connect(...);
 f.awaitUninterruptibly();

 // Now we are sure the future is completed.
 assert f.isDone();

 if (f.isCancelled()) {
     // Connection attempt cancelled by user
 } else if (!f.isSuccess()) {
     f.cause().printStackTrace();
 } else {
     // Connection established successfully
 }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 接著上節(jié) condition_varible ,本節(jié)主要介紹future的內(nèi)容,練習(xí)代碼地址。本文參考http:/...
    jorion閱讀 15,040評(píng)論 1 5
  • 第三章 Java內(nèi)存模型 3.1 Java內(nèi)存模型的基礎(chǔ) 通信在共享內(nèi)存的模型里,通過(guò)寫(xiě)-讀內(nèi)存中的公共狀態(tài)進(jìn)行隱...
    澤毛閱讀 4,500評(píng)論 2 21
  • 一.線(xiàn)程安全性 線(xiàn)程安全是建立在對(duì)于對(duì)象狀態(tài)訪(fǎng)問(wèn)操作進(jìn)行管理,特別是對(duì)共享的與可變的狀態(tài)的訪(fǎng)問(wèn) 解釋下上面的話(huà): ...
    黃大大吃不胖閱讀 953評(píng)論 0 3
  • 1、線(xiàn)程安全與鎖 線(xiàn)程安全的本質(zhì),在于 存在了共享的可變狀態(tài) status, 在多線(xiàn)程共同操作狀態(tài)變量時(shí),當(dāng)計(jì)算的...
    軒居晨風(fēng)閱讀 413評(píng)論 1 1
  • 上了大學(xué)之后,個(gè)人可支配的時(shí)間變得多了,不是一般多,而是特別多,所以才導(dǎo)致我迷茫了整整一年。 高中三年,累死累活,...
    蘇宸閱讀 582評(píng)論 4 0

友情鏈接更多精彩內(nèi)容