public static void join(final Thread thread, final long timeoutMilliseconds) {
    final long tilt = System.currentTimeMillis() + timeoutMilliseconds;
    final long incrementalWait = jitterInterval(timeoutMilliseconds);
    final long start = System.currentTimeMillis();
    for (;;) {
      // I really do *not* understand why this check is necessary
      // but it is, at least with JDK 1.6. According to the source code
      // and the javadocs, one would think that join() would exit immediately
      // if the thread is dead. However, I can tell you from experimentation
      // that this is not the case. :-( djp 2008-12-08
      if (!thread.isAlive()) {
        break;
      }
      try {
        thread.join(incrementalWait);
      } catch (InterruptedException e) {
        fail("interrupted");
      }
      if (System.currentTimeMillis() >= tilt) {
        break;
      }
    } // for
    if (thread.isAlive()) {
      logger.info("HUNG THREAD");
      ThreadUtils.dumpStackTrace(thread, thread.getStackTrace());
      ThreadUtils.dumpMyThreads();
      thread.interrupt(); // We're in trouble!
      fail("Thread did not terminate after " + timeoutMilliseconds + " ms: " + thread);
    }
    long elapsedMs = (System.currentTimeMillis() - start);
    if (elapsedMs > 0) {
      String msg = "Thread " + thread + " took " + elapsedMs + " ms to exit.";
      logger.info(msg);
    }
  }
Wait for a thread to join.

@param thread thread to wait on
@param timeoutMilliseconds maximum time to wait
@throws AssertionError if the thread does not terminate
geode-dunit/src/main/java/org/apache/geode/test/dunit/ThreadUtils.java