code: synchronized void recoverChannel(boolean viaConnectionRecovery) throws Exception {
      recoveryPending.set(false);
      if (circuit.isClosed())
        return;
  
      if (recoveryStats == null) {
        recoveryConsumers = consumerDeclarations.isEmpty() ? null
          : new LinkedHashMap<String, ConsumerDeclaration>(consumerDeclarations);
        recoveryStats = new RecurringStats(config.getChannelRecoveryPolicy());
        recoveryStats.incrementTime();
      } else if (recoveryStats.isPolicyExceeded()) {
        recoveryFailed(lastShutdownSignal);
        if (!viaConnectionRecovery)
          return;
      }
  
      try {
        notifyRecoveryStarted();
        delegate = callWithRetries(new Callable<Channel>() {
          @Override
          public Channel call() throws Exception {
            log.info("Recovering {}", ChannelHandler.this);
            previousMaxDeliveryTag = maxDeliveryTag;
            Channel channel = connectionHandler.createChannel(delegate.getChannelNumber());
            migrateConfiguration(channel);
            log.info("Recovered {}", ChannelHandler.this);
            return channel;
          }
        }, config.getChannelRecoveryPolicy(), recoveryStats, config.getRecoverableExceptions(), true,
          false);
        notifyRecovery();
        recoverConsumers(!viaConnectionRecovery);
        recoverySucceeded();
      } catch (Exception e) {
        ShutdownSignalException sse = Exceptions.extractCause(e, ShutdownSignalException.class);
        if (sse != null) {
          if (Exceptions.isConnectionClosure(sse))
            throw e;
        } else if (recoveryStats.isPolicyExceeded())
          recoveryFailed(e);
      }
    }
docs: Atomically recovers the channel.
  
  @throws Exception when recovery fails due to a connection closure