@SuppressWarnings("deprecation")
  protected void afterEnd(Map flags, Task<?> task) {
    activeTaskCount.decrementAndGet();
    incompleteTaskCount.decrementAndGet();

    if (log.isTraceEnabled()) log.trace(this + " afterEnd, task: " + task);
    ExecutionUtils.invoke(flags.get("newTaskEndCallback"), task);
    List l = (List) flags.get("tagLinkedPreprocessors");
    Collections.reverse(l);
    for (Object li : l) {
      TaskPreprocessor t = (TaskPreprocessor) li;
      t.onEnd(flags, task);
    }

    PerThreadCurrentTaskHolder.perThreadCurrentTask.remove();
    ((BasicTask) task).endTimeUtc = System.currentTimeMillis();
    // clear thread _after_ endTime set, so we won't get a null thread when there is no end-time
    if (RENAME_THREADS) {
      String newThreadName = "brooklyn-" + LanguageUtils.newUid();
      ((BasicTask) task).thread.setName(newThreadName);
    }
    ((BasicTask) task).thread = null;
    synchronized (task) {
      task.notifyAll();
    }

    ExpirationPolicy expirationPolicy = (ExpirationPolicy) flags.get("expirationPolicy");
    if (expirationPolicy == null) expirationPolicy = ExpirationPolicy.IMMEDIATE;
    if (expirationPolicy == ExpirationPolicy.IMMEDIATE) {
      for (Object t : ((BasicTask) task).tags) {
        getMutableTasksWithTag(t).remove(task);
      }
    }
  }