@Test
  public void testCancelled() throws InterruptedException, ExecutionException {
    Task<List<?>> t =
        Tasks.sequential(sayTask("1"), sayTask("2a", Duration.THIRTY_SECONDS, "2b"), sayTask("3"));
    ec.submit(t);
    synchronized (messages) {
      while (messages.size() <= 1) messages.wait();
    }
    Assert.assertEquals(messages, Arrays.asList("1", "2a"));
    Time.sleep(Duration.millis(50));
    t.cancel(true);
    Assert.assertTrue(t.isDone());
    // 2 should get cancelled, and invoke the cancellation semaphore
    // 3 should get cancelled and not run at all
    Assert.assertEquals(messages, Arrays.asList("1", "2a"));

    // Need to ensure that 2 has been started; race where we might cancel it before its run method
    // is even begun. Hence doing "2a; pause; 2b" where nothing is interruptable before pause.
    Assert.assertTrue(cancellations.tryAcquire(10, TimeUnit.SECONDS));

    Iterator<Task<?>> ci = ((HasTaskChildren) t).getChildren().iterator();
    Assert.assertEquals(ci.next().get(), "1");
    Task<?> task2 = ci.next();
    Assert.assertTrue(task2.isBegun());
    Assert.assertTrue(task2.isDone());
    Assert.assertTrue(task2.isCancelled());

    Task<?> task3 = ci.next();
    Assert.assertFalse(task3.isBegun());
    Assert.assertTrue(task2.isDone());
    Assert.assertTrue(task2.isCancelled());

    // but we do _not_ get a mutex from task3 as it does not run (is not interrupted)
    Assert.assertEquals(cancellations.availablePermits(), 0);
  }
  @SuppressWarnings("deprecation")
  protected void beforeStart(Map flags, Task<?> task) {
    activeTaskCount.incrementAndGet();

    // set thread _before_ start time, so we won't get a null thread when there is a start-time
    if (log.isTraceEnabled()) log.trace("" + this + " beforeStart, task: " + task);
    if (!task.isCancelled()) {
      ((BasicTask) task).thread = Thread.currentThread();
      if (RENAME_THREADS) {
        String newThreadName =
            "brooklyn-"
                + CaseFormat.LOWER_HYPHEN.to(
                    CaseFormat.LOWER_CAMEL, task.getDisplayName().replace(" ", ""))
                + "-"
                + task.getId().substring(0, 8);
        ((BasicTask) task).thread.setName(newThreadName);
      }
      PerThreadCurrentTaskHolder.perThreadCurrentTask.set(task);
      ((BasicTask) task).startTimeUtc = System.currentTimeMillis();
    }
    for (Object to : (Collection) flags.get("tagLinkedPreprocessors")) {
      TaskPreprocessor t = (TaskPreprocessor) to;
      t.onStart(flags, task);
    }
    ExecutionUtils.invoke(flags.get("newTaskStartCallback"), task);
  }
  protected void beforeStart(Map<?, ?> flags, Task<?> task) {
    activeTaskCount.incrementAndGet();

    // set thread _before_ start time, so we won't get a null thread when there is a start-time
    if (log.isTraceEnabled()) log.trace("" + this + " beforeStart, task: " + task);
    if (!task.isCancelled()) {
      ((TaskInternal<?>) task).setThread(Thread.currentThread());
      if (RENAME_THREADS) {
        String newThreadName =
            "brooklyn-"
                + CaseFormat.LOWER_HYPHEN.to(
                    CaseFormat.LOWER_CAMEL, task.getDisplayName().replace(" ", ""))
                + "-"
                + task.getId().substring(0, 8);
        task.getThread().setName(newThreadName);
      }
      PerThreadCurrentTaskHolder.perThreadCurrentTask.set(task);
      ((TaskInternal<?>) task).setStartTimeUtc(System.currentTimeMillis());
    }
    ExecutionUtils.invoke(flags.get("newTaskStartCallback"), task);
  }