@Override
    public void run() {
      try {
        channel.channel.register(boss.selector, SelectionKey.OP_CONNECT, channel);
      } catch (ClosedChannelException e) {
        channel.worker.close(channel, succeededFuture(channel));
      }

      int connectTimeout = channel.getConfig().getConnectTimeoutMillis();
      if (connectTimeout > 0) {
        channel.connectDeadlineNanos = System.nanoTime() + connectTimeout * 1000000L;
      }
    }
    @Override
    public void run() {
      boolean shutdown = false;
      Selector selector = this.selector;
      long lastConnectTimeoutCheckTimeNanos = System.nanoTime();
      for (; ; ) {
        wakenUp.set(false);

        try {
          int selectedKeyCount = selector.select(10);

          // 'wakenUp.compareAndSet(false, true)' is always evaluated
          // before calling 'selector.wakeup()' to reduce the wake-up
          // overhead. (Selector.wakeup() is an expensive operation.)
          //
          // However, there is a race condition in this approach.
          // The race condition is triggered when 'wakenUp' is set to
          // true too early.
          //
          // 'wakenUp' is set to true too early if:
          // 1) Selector is waken up between 'wakenUp.set(false)' and
          //    'selector.select(...)'. (BAD)
          // 2) Selector is waken up between 'selector.select(...)' and
          //    'if (wakenUp.get()) { ... }'. (OK)
          //
          // In the first case, 'wakenUp' is set to true and the
          // following 'selector.select(...)' will wake up immediately.
          // Until 'wakenUp' is set to false again in the next round,
          // 'wakenUp.compareAndSet(false, true)' will fail, and therefore
          // any attempt to wake up the Selector will fail, too, causing
          // the following 'selector.select(...)' call to block
          // unnecessarily.
          //
          // To fix this problem, we wake up the selector again if wakenUp
          // is true immediately after selector.select(...).
          // It is inefficient in that it wakes up the selector for both
          // the first case (BAD - wake-up required) and the second case
          // (OK - no wake-up required).

          if (wakenUp.get()) {
            selector.wakeup();
          }

          processRegisterTaskQueue();

          if (selectedKeyCount > 0) {
            processSelectedKeys(selector.selectedKeys());
          }

          // Handle connection timeout every 10 milliseconds approximately.
          long currentTimeNanos = System.nanoTime();
          if (currentTimeNanos - lastConnectTimeoutCheckTimeNanos >= 10 * 1000000L) {
            lastConnectTimeoutCheckTimeNanos = currentTimeNanos;
            processConnectTimeout(selector.keys(), currentTimeNanos);
          }

          // Exit the loop when there's nothing to handle.
          // The shutdown flag is used to delay the shutdown of this
          // loop to avoid excessive Selector creation when
          // connection attempts are made in a one-by-one manner
          // instead of concurrent manner.
          if (selector.keys().isEmpty()) {
            if (shutdown
                || bossExecutor instanceof ExecutorService
                    && ((ExecutorService) bossExecutor).isShutdown()) {

              synchronized (startStopLock) {
                if (registerTaskQueue.isEmpty() && selector.keys().isEmpty()) {
                  started = false;
                  try {
                    selector.close();
                  } catch (IOException e) {
                    if (logger.isWarnEnabled()) {
                      logger.warn("Failed to close a selector.", e);
                    }

                  } finally {
                    this.selector = null;
                  }
                  break;
                } else {
                  shutdown = false;
                }
              }
            } else {
              // Give one more second.
              shutdown = true;
            }
          } else {
            shutdown = false;
          }
        } catch (Throwable t) {
          if (logger.isWarnEnabled()) {
            logger.warn("Unexpected exception in the selector loop.", t);
          }

          // Prevent possible consecutive immediate failures.
          try {
            Thread.sleep(1000);
          } catch (InterruptedException e) {
            // Ignore.
          }
        }
      }
    }