public void run() {
    synchronized (started_lock) {
      m_TimerThread = m_BrokerCore.getTimerThread();

      // advertise that we will be publishing heartbeat related messages
      advertiseHeartbeat();
      advertiseFailureDetected();

      // set the initial heartbeat timer
      m_TimerThread.setTimer(new TimerEvent(this, m_HeartbeatInterval, HEARTBEAT_INTERVAL_TIMER));

      // wake up threads waiting for HeartbeatPublisher to start
      started = true;
      started_lock.notifyAll();
    }

    while (started) {
      try {
        sleep(DEFAULT_SLEEP_TIME);
      } catch (InterruptedException ignored) {
      }

      if (!started) break;

      synchronized (this) {
        // check if neighbor list changed
        if (m_NeighborListChanged) {
          // TODO: process changed neighbor list
          m_NeighborListChanged = false;
        }

        // check for expired events
        while (m_ReturnedEventsQ != null) {
          TimerEvent event = m_ReturnedEventsQ;

          // process the event
          if (event.getStatus() == TimerEvent.TIMER_STATUS_EXPIRED) {
            if (event.getType() == HEARTBEAT_INTERVAL_TIMER) {
              // send the next batch of heartbeats
              if (m_PublishHeartbeats) publishHeartbeats();
              // reset the interval timer
              m_TimerThread.setTimer(
                  new TimerEvent(this, m_HeartbeatInterval, HEARTBEAT_INTERVAL_TIMER));
            } else if (event.getType() == HEARTBEAT_TIMEOUT_TIMER) {
              heartbeatLogger.info(
                  "Broker " + event.getAttachment() + " did not reply to a heartbeat");

              // get the name of the offending broker
              String broker = (String) event.getAttachment();

              // a broker heartbeat timed out, increment the fail count
              Map<MessageDestination, OutputQueue> neighbors1 =
                  m_BrokerCore.getOverlayManager().getORT().getBrokerQueues();
              synchronized (neighbors1) {
                for (MessageDestination md : neighbors1.keySet()) {
                  if (md.getDestinationID().equals(broker)) {
                    int failCount = md.incrementFailCount();
                    if (failCount >= m_FailureThreshold) {
                      publishFailureDetected(broker);
                      break;
                    }
                  }
                }
              }
            }
          }
          m_ReturnedEventsQ = event.getNext();
        }
      }
    }
  }