public void addToExpirationQueue(TezSessionPoolSession session) {
    long jitterModMs = (long)(sessionLifetimeJitterMs * rdm.nextFloat());
    session.setExpirationNs(System.nanoTime() + (sessionLifetimeMs + jitterModMs) * 1000000L);
    LOG.debug("Adding a pool session [{}] to expiration queue", this);
    // Expiration queue is synchronized and notified upon when adding elements. Without jitter, we
    // wouldn't need this, and could simple look at the first element and sleep for the wait time.
    // However, when many things are added at once, it may happen that we will see the one that
    // expires later first, and will sleep past the earlier expiration times. When we wake up we
    // may kill many sessions at once. To avoid this, we will add to queue under lock and recheck
    // time before we wait. We don't have to worry about removals; at worst we'd wake up in vain.
    // Example: expirations of 1:03:00, 1:00:00, 1:02:00 are added (in this order due to jitter).
    // If the expiration threads sees that 1:03 first, it will sleep for 1:03, then wake up and
    // kill all 3 sessions at once because they all have expired, removing any effect from jitter.
    // Instead, expiration thread rechecks the first queue item and waits on the queue. If nothing
    // is added to the queue, the item examined is still the earliest to be expired. If someone
    // adds to the queue while it is waiting, it will notify the thread and it would wake up and
    // recheck the queue.
    synchronized (expirationQueue) {
      expirationQueue.add(session);
      expirationQueue.notifyAll();
    }
  }
Logic for the thread that tracks session expiration and restarts sessions in background.
ql/src/java/org/apache/hadoop/hive/ql/exec/tez/SessionExpirationTracker.java