@Override
  public void stop() {
    if (_stopping.compareAndSet(false, true)) {
      _ctl.setStopping(true);

      final int numSessions = _sessions.length;

      for (int i = 0; i < numSessions; i++) {
        final SessionWrapper s = _sessions[i];

        MessageQueue q = s._queue;

        q.add(new NullMessage()); // wake up queue
      }

      _fullyFlushed = false;
    }
  }
  @Override
  public void handlerStatusChange(MessageHandler handler, boolean connected) {
    final int numSessions = _sessions.length;

    boolean allDisconnected = true;

    for (int i = 0; i < numSessions; i++) {
      SessionWrapper sessW = _sessions[i];

      if (sessW._session == handler) {
        if (connected != sessW._connected) {
          final NonBlockingSession sess = sessW._session;

          _log.info(
              "MultiSession OutDispatcher "
                  + getComponentId()
                  + " : "
                  + ((connected) ? "CONNECTED" : "DISCONNECTED")
                  + " with "
                  + sess.getComponentId()
                  + ", canHandle="
                  + sess.canHandle()
                  + ", isLoggedIn="
                  + sess.isLoggedIn());

          sessW._connected = connected;
        }
      }

      if (sessW._connected) {
        allDisconnected = false;
      }
    }

    _fullyFlushed = false;

    synchronized (_disconnectLock) { // force mem barrier
      _allDisconnected = allDisconnected;
    }

    _ctl.statusChange();
  }
  @Override
  public void handleExecutionException(Exception ex) {
    final NonBlockingSession sess = _curSessW._session;

    if (_curMsg != null && sess != null) {
      _log.warn(
          "SessionThreadedDispatcher "
              + getComponentId()
              + ", msgSeqNum="
              + _curMsg.getMsgSeqNum()
              + ", sess="
              + sess.getComponentId()
              + " exception "
              + ex.getMessage());
    }

    flush(_curSessW);

    // some problem, possibly disconnect, poke controller to wake up anything waiting on controller
    // passive lock
    _ctl.statusChange(); // Mem barrier
  }
  public MultiSessionThreadedDispatcher(String id, ControlThread ctl) {
    _ctl = ctl;
    _id = id;

    ctl.register(this);
  }
 @Override
 public synchronized void start() {
   _ctl.start();
 }