@Override
  public void run() {
    LOG.info("Starting Cleaner thread");
    try {
      do {
        TxnStore.MutexAPI mutex =  shouldUseMutex ? txnHandler.getMutexAPI() : new NoMutex();
        metadataCache.invalidate();
        long startedAt = -1;

        // Make sure nothing escapes this run method and kills the metastore at large,
        // so wrap it in a big catch Throwable statement.
        try (AutoCloseable closeable = mutex.acquireLock(TxnStore.MUTEX_KEY.Cleaner.name())) {
          startedAt = System.currentTimeMillis();

          if (metricsEnabled) {
            stopCycleUpdater();
            startCycleUpdater(HiveConf.getTimeVar(conf,
                    HiveConf.ConfVars.HIVE_COMPACTOR_CLEANER_DURATION_UPDATE_INTERVAL, TimeUnit.MILLISECONDS),
                    new CleanerCycleUpdater(MetricsConstants.COMPACTION_CLEANER_CYCLE_DURATION, startedAt));
          }

          for (TaskHandler cleanupHandler : cleanupHandlers) {
            try {
              CompactorUtil.checkInterrupt(CLASS_NAME);
              List<Runnable> tasks = cleanupHandler.getTasks();
              List<CompletableFuture<Void>> asyncTasks = new ArrayList<>();
              for (Runnable task : tasks) {
                CompletableFuture<Void> asyncTask = CompletableFuture.runAsync(
                                task, cleanerExecutor)
                        .exceptionally(t -> {
                          LOG.error("Error clearing due to :", t);
                          return null;
                        });
                asyncTasks.add(asyncTask);
              }
              //Use get instead of join, so we can receive InterruptedException and shutdown gracefully
              CompletableFuture.allOf(asyncTasks.toArray(new CompletableFuture[0])).get();
            } catch (InterruptedException e) {
              Thread.currentThread().interrupt();
              return;
            } catch (Throwable t) {
              LOG.error("Caught an exception while executing RequestHandler loop : {} of compactor cleaner, {}",
                       cleanupHandler.getClass().getName(), t.getMessage());
              throw t;
            }
          }
          CompactorUtil.checkInterrupt(CLASS_NAME);
        } catch (InterruptedException e) {
          Thread.currentThread().interrupt();
          return;
        } catch (Throwable t) {
          LOG.error("Caught an exception in the main loop of compactor cleaner, {}",
              StringUtils.stringifyException(t));
        } finally {
          if (metricsEnabled) {
            updateCycleDurationMetric(MetricsConstants.COMPACTION_CLEANER_CYCLE_DURATION, startedAt);
          }
          stopCycleUpdater();
        }
        // Now, go back to bed until it's time to do this again
        doPostLoopActions(System.currentTimeMillis() - startedAt);
      } while (!stop.get());
    } catch (InterruptedException ie) {
      Thread.currentThread().interrupt();
      LOG.error("Compactor cleaner thread interrupted, exiting {}",
        StringUtils.stringifyException(ie));
    } finally {
      if (Thread.currentThread().isInterrupted()) {
        LOG.info("Interrupt received, Cleaner is shutting down.");
      }
      if (cleanerExecutor != null) {
        cleanerExecutor.shutdownNow();
      }
    }
  }
A class to clean directories after compactions.  This will run in a separate thread.
ql/src/java/org/apache/hadoop/hive/ql/txn/compactor/Cleaner.java