code: @Override
      public boolean close(int error, String reason, Callback callback) {
          while (true) {
              CloseState current = closed.get();
              switch (current) {
                  case NOT_CLOSED: {
                      if (closed.compareAndSet(current, CloseState.LOCALLY_CLOSED)) {
                          GoAwayFrame frame = newGoAwayFrame(error, reason);
                          control(null, callback, frame);
                          return true;
                      }
                      break;
                  }
                  default: {
                      if (log.isDebugEnabled())
                          log.debug("Ignoring close {}/{}, already closed", error, reason);
                      callback.succeeded();
                      return false;
                  }
              }
          }
      }
docs: Invoked internally and by applications to send a GO_AWAY frame to the
  other peer. We check the close state to act appropriately:
  <ul>
  <li>NOT_CLOSED: we move to LOCALLY_CLOSED and queue a GO_AWAY. When the
  GO_AWAY has been written, it will only cause the output to be shut
  down (not the connection closed), so that the application can still
  read frames arriving from the other peer.
  Ideally the other peer will notice the GO_AWAY and close the connection.
  When that happen, we close the connection from {@link #onShutdown()}.
  Otherwise, the idle timeout mechanism will close the connection, see
  {@link #onIdleTimeout()}.</li>
  <li>In all other cases, we do nothing since other methods are already
  performing their actions.</li>
  </ul>
  
  @param error    the error code
  @param reason   the reason
  @param callback the callback to invoke when the operation is complete
  @see #onGoAway(GoAwayFrame)
  @see #onShutdown()
  @see #onIdleTimeout()