@Override
    public Void call() throws Exception {
      while (!isShutdown.get() && !Thread.currentThread().isInterrupted()) {
        scheduleLock.lock();
        try {
          while (!pendingScheduleInvocations.get()) {
            scheduleCondition.await();
          }
        } catch (InterruptedException e) {
          if (isShutdown.get()) {
            LOG.info("Scheduler thread interrupted after shutdown");
            break;
          } else {
            LOG.warn("Scheduler thread interrupted without being shutdown");
            throw new RuntimeException("Scheduler thread interrupted without being shutdown", e);
          }
        } finally {
          scheduleLock.unlock();
        }

        // Set pending to false since scheduling is about to run. Any triggers up to this point
        // will be handled in the next run.
        // A new request may come in right after this is set to false, but before the actual scheduling.
        // This will be handled in this run, but will cause an immediate run after, which is harmless.
        // isClusterCapacityFull helps in such runs bailing out when we know no resources are available.
        // pendingScheduleInvocations is mainly to handle a trySchedulingPendingTasks request while in the middle of
        // a run - since the event which triggered it may not be processed for all tasks in the run.
        pendingScheduleInvocations.set(false);
        // Schedule outside of the scheduleLock - which should only be used to wait on the condition.
        try {
          schedulePendingTasks();
        } catch (InterruptedException ie) {
          if (isShutdown.get()) {
            return null; // We are good.
          }
          LOG.error("Scheduler thread was interrupte without shutdown and will now exit", ie);
          throw ie;
        } catch (Throwable t) {
          // TODO: we might as well kill the AM at this point. How do we do that from here?
          LOG.error("Fatal error: scheduler thread has failed and will now exit", t);
          throw (t instanceof Exception) ? (Exception)t : new Exception(t);
        }
      }
      return null;
    }
Go through the running tasks Tree in descending priority and find a candidate to preempt. The candidate should be:
1. lower priority than forTask
2. below forTask in the DAG
3. not considered already for preemption
A successful candidate is added to the preemptionCandidates queue for preemption by the scheduling loop.
@param runningTasks Tree of running tasks
@param forTask Task to find preemption candidate for
@param preemptHosts Hosts preference
@return true when preemption candidate is found
llap-tez/src/java/org/apache/hadoop/hive/llap/tezplugins/LlapTaskSchedulerService.java