void checkIO() {
    long timeout;

    if (NewConnections.size() > 0) {
      timeout = -1;
    } else if (!Timers.isEmpty()) {
      long now = new Date().getTime();
      long k = Timers.firstKey();
      long diff = k - now;

      if (diff <= 0) timeout = -1; // don't wait, just poll once
      else timeout = diff;
    } else {
      timeout = 0; // wait indefinitely
    }

    try {
      if (timeout == -1) mySelector.selectNow();
      else mySelector.select(timeout);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  void processIO() {
    Iterator<SelectionKey> it = mySelector.selectedKeys().iterator();
    while (it.hasNext()) {
      SelectionKey k = it.next();
      it.remove();

      if (k.isConnectable()) isConnectable(k);
      else if (k.isAcceptable()) isAcceptable(k);
      else {
        if (k.isWritable()) isWritable(k);

        if (k.isReadable()) isReadable(k);
      }
    }
  }
  void close() {
    try {
      if (mySelector != null) mySelector.close();
    } catch (IOException e) {
    }
    mySelector = null;

    // run down open connections and sockets.
    Iterator<ServerSocketChannel> i = Acceptors.values().iterator();
    while (i.hasNext()) {
      try {
        i.next().close();
      } catch (IOException e) {
      }
    }

    // 29Sep09: We create an ArrayList of the existing connections, then iterate over
    // that to call unbind on them. This is because an unbind can trigger a reconnect,
    // which will add to the Connections HashMap, causing a ConcurrentModificationException.
    // XXX: The correct behavior here would be to latch the various reactor methods to return
    // immediately if the reactor is shutting down.
    ArrayList<EventableChannel> conns = new ArrayList<EventableChannel>();
    Iterator<EventableChannel> i2 = Connections.values().iterator();
    while (i2.hasNext()) {
      EventableChannel ec = i2.next();
      if (ec != null) {
        conns.add(ec);
      }
    }
    Connections.clear();

    ListIterator<EventableChannel> i3 = conns.listIterator(0);
    while (i3.hasNext()) {
      EventableChannel ec = i3.next();
      eventCallback(ec.getBinding(), EM_CONNECTION_UNBOUND, null);
      ec.close();

      EventableSocketChannel sc = (EventableSocketChannel) ec;
      if (sc != null && sc.isAttached()) DetachedConnections.add(sc);
    }

    ListIterator<EventableSocketChannel> i4 = DetachedConnections.listIterator(0);
    while (i4.hasNext()) {
      EventableSocketChannel ec = i4.next();
      ec.cleanup();
    }
    DetachedConnections.clear();
  }
  public void run() {
    try {
      mySelector = Selector.open();
      bRunReactor = true;
    } catch (IOException e) {
      throw new RuntimeException("Could not open selector", e);
    }

    while (bRunReactor) {
      runLoopbreaks();
      if (!bRunReactor) break;

      runTimers();
      if (!bRunReactor) break;

      removeUnboundConnections();
      checkIO();
      addNewConnections();
      processIO();
    }

    close();
  }
 public void signalLoopbreak() {
   loopBreaker.set(true);
   if (mySelector != null) mySelector.wakeup();
 }