Interface ChannelGroupFuture

  • All Superinterfaces:
    io.netty.util.concurrent.Future<Void>, Future<Void>, Iterable<ChannelFuture>

    public interface ChannelGroupFuture
    extends io.netty.util.concurrent.Future<Void>, Iterable<ChannelFuture>
    The result of an asynchronous ChannelGroup operation. ChannelGroupFuture is composed of ChannelFutures which represent the outcome of the individual I/O operations that affect the Channels in the ChannelGroup.

    All I/O operations in ChannelGroup are asynchronous. It means any I/O calls will return immediately with no guarantee that the requested I/O operations have been completed at the end of the call. Instead, you will be returned with a ChannelGroupFuture instance which tells you when the requested I/O operations have succeeded, failed, or cancelled.

    Various methods are provided to let you check if the I/O operations has been completed, wait for the completion, and retrieve the result of the I/O operation. It also allows you to add more than one ChannelGroupFutureListener so you can get notified when the I/O operation have been completed.

    Prefer addListener(GenericFutureListener) to await()

    It is recommended to prefer addListener(GenericFutureListener) to await() wherever possible to get notified when I/O operations are done and to do any follow-up tasks.

    addListener(GenericFutureListener) is non-blocking. It simply adds the specified ChannelGroupFutureListener to the ChannelGroupFuture, and I/O thread will notify the listeners when the I/O operations associated with the future is done. ChannelGroupFutureListener yields the best performance and resource utilization because it does not block at all, but it could be tricky to implement a sequential logic if you are not used to event-driven programming.

    By contrast, await() is a blocking operation. Once called, the caller thread blocks until all I/O operations are done. It is easier to implement a sequential logic with await(), but the caller thread blocks unnecessarily until all I/O operations are done and there's relatively expensive cost of inter-thread notification. Moreover, there's a chance of dead lock in a particular circumstance, which is described below.

    Do not call await() inside ChannelHandler

    The event handler methods in ChannelHandler is often called by an I/O thread. If await() is called by an event handler method, which is called by the I/O thread, the I/O operation it is waiting for might never be complete because await() can block the I/O operation it is waiting for, which is a dead lock.

     // BAD - NEVER DO THIS
     @Override
     public void messageReceived(ChannelHandlerContext ctx, ShutdownMessage msg) {
         ChannelGroup allChannels = MyServer.getAllChannels();
         ChannelGroupFuture future = allChannels.close();
         future.awaitUninterruptibly();
         // Perform post-shutdown operation
         // ...
    
     }
    
     // GOOD
     @Override
     public void messageReceived(ChannelHandlerContext ctx, ShutdownMessage msg) {
         ChannelGroup allChannels = MyServer.getAllChannels();
         ChannelGroupFuture future = allChannels.close();
         future.addListener(new ChannelGroupFutureListener() {
             public void operationComplete(ChannelGroupFuture future) {
                 // Perform post-closure operation
                 // ...
             }
         });
     }
     

    In spite of the disadvantages mentioned above, there are certainly the cases where it is more convenient to call await(). In such a case, please make sure you do not call await() in an I/O thread. Otherwise, IllegalStateException will be raised to prevent a dead lock.

    • Method Detail

      • isSuccess

        boolean isSuccess()
        Returns true if and only if all I/O operations associated with this future were successful without any failure.
        Specified by:
        isSuccess in interface io.netty.util.concurrent.Future<Void>
      • isPartialSuccess

        boolean isPartialSuccess()
        Returns true if and only if the I/O operations associated with this future were partially successful with some failure.
      • isPartialFailure

        boolean isPartialFailure()
        Returns true if and only if the I/O operations associated with this future have failed partially with some success.
      • addListener

        ChannelGroupFuture addListener​(io.netty.util.concurrent.GenericFutureListener<? extends io.netty.util.concurrent.Future<? super Void>> listener)
        Specified by:
        addListener in interface io.netty.util.concurrent.Future<Void>
      • addListeners

        ChannelGroupFuture addListeners​(io.netty.util.concurrent.GenericFutureListener<? extends io.netty.util.concurrent.Future<? super Void>>... listeners)
        Specified by:
        addListeners in interface io.netty.util.concurrent.Future<Void>
      • removeListener

        ChannelGroupFuture removeListener​(io.netty.util.concurrent.GenericFutureListener<? extends io.netty.util.concurrent.Future<? super Void>> listener)
        Specified by:
        removeListener in interface io.netty.util.concurrent.Future<Void>
      • removeListeners

        ChannelGroupFuture removeListeners​(io.netty.util.concurrent.GenericFutureListener<? extends io.netty.util.concurrent.Future<? super Void>>... listeners)
        Specified by:
        removeListeners in interface io.netty.util.concurrent.Future<Void>
      • awaitUninterruptibly

        ChannelGroupFuture awaitUninterruptibly()
        Specified by:
        awaitUninterruptibly in interface io.netty.util.concurrent.Future<Void>
      • syncUninterruptibly

        ChannelGroupFuture syncUninterruptibly()
        Specified by:
        syncUninterruptibly in interface io.netty.util.concurrent.Future<Void>