@Override
    public void run() {
      Stopwatch sw = Stopwatch.createUnstarted();
      Map<String, GcTimes> gcTimesBeforeSleep = getGcTimes();
      while (shouldRun) {
        sw.reset().start();
        try {
          Thread.sleep(SLEEP_INTERVAL_MS);
        } catch (InterruptedException ie) {
          return;
        }

        long extraSleepTime = sw.elapsed(TimeUnit.MILLISECONDS) - SLEEP_INTERVAL_MS;
        Map<String, GcTimes> gcTimesAfterSleep = getGcTimes();

        if (extraSleepTime > infoThresholdMs) {
          Set<String> gcBeanNames =
            Sets.intersection(gcTimesAfterSleep.keySet(), gcTimesBeforeSleep.keySet());
          List<String> gcDiffs = Lists.newArrayList();
          for (String name : gcBeanNames) {
            GcTimes diff = gcTimesAfterSleep.get(name).subtract(gcTimesBeforeSleep.get(name));
            if (diff.gcCount != 0) {
              gcDiffs.add("GC pool '" + name + "' had collection(s): " + diff.toString());
            }
          }

          updateMetrics(extraSleepTime, !gcDiffs.isEmpty());

          if (extraSleepTime > warnThresholdMs) {
            LOG.warn(formatMessage(extraSleepTime, gcDiffs));
          } else {
            LOG.info(formatMessage(extraSleepTime, gcDiffs));
          }
        }
        gcTimesBeforeSleep = gcTimesAfterSleep;
      }
    }
log INFO if we detect a pause longer than this threshold
hbase-server/src/main/java/org/apache/hadoop/hbase/util/JvmPauseMonitor.java