B/c there’s a slightly time loss during the time done is set to true and we check it ourselves, and only then we re-invoke start(), I don’t think class Countdown fits fully the requirements of your “sequencers”. 
Just made a variant of it called Interval, where done is set to true over & over at a fixed period time.
We now need to call Interval::intervalDone() in order to check whether the previous interval had been completed.
As a bonus, in place or in addition to check Interval::intervalDone(), we can also assign our own customized Interval.Callback::run() to the field Interval::callback. 
Well, better see it for yourself. Here’s the code for both the “.pde” example and the “.java” library itself: 
“IntervalClass.pde”:
/** 
 * Interval Class (v1.0)
 * GoToLoop (2018/Jul/09)
 *
 * https://Discourse.Processing.org/t/
 * sequencer-firing-multiple-events-or-one-step-behind/1571/12
 */
import gotoloop.time.Interval;
static final float SECS = 1;
static final int WAIT_TIME = (int) (SECS * 1000);
final Interval interval = new Interval(WAIT_TIME);
color bg;
void setup() {
  size(300, 180);
  smooth(3);
  frameRate(60);
  colorMode(RGB);
  fill(#FFFF00);
  textSize(0100);
  textAlign(CENTER, CENTER);
  final int m = millis(), t = m + WAIT_TIME;
  interval.start();
  println(m, t, t - m, TAB, interval);
  createCallback();
}
void draw() {
  if (interval.intervalDone())  bg = randomColor();
  background(bg);
  final String txt = millis() + "\n" + frameCount;
  text(txt, width>>1, height>>1);
}
color randomColor() {
  return (color) random(PImage.ALPHA_MASK);
}
void createCallback() {
  interval.callback = new Interval.Callback() {
    @Override public void run() {
      fill(randomColor());
    }
  };
}
“Interval.java”:
/** 
 * Interval Class (v1.0)
 * GoToLoop (2018/Jul/09)
 *
 * https://Discourse.Processing.org/t/
 * sequencer-firing-multiple-events-or-one-step-behind/1571/12
 */
package gotoloop.time;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
public class Interval {
  protected static final Timer t = new Timer("Interval");
  protected final AtomicBoolean done = new AtomicBoolean(true);
  public Callback callback;
  public TimerTask task;
  public int period;
  public boolean precise = true;
  public Interval() {
  }
  public Interval(final int waitTime) { // milliseconds
    this(waitTime, null);
  }
  public Interval(final int waitTime, final Callback listener) {
    period = Math.abs(waitTime);
    callback = listener;
  }
  @Override public String toString() {
    return "Period: " + period;
  }
  public Interval start() {
    stop().done.set(false);
    task = new Timeout();
    if (precise)  t.scheduleAtFixedRate(task, period, period);
    else          t.schedule(task, period, period);
    return this;
  }
  public Interval stop() {
    if (task != null)  task.cancel();
    return this;
  }
  public boolean intervalDone() {
    return done.compareAndSet(true, false);
  }
  @FunctionalInterface public interface Callback {
    void run();
  }
  protected class Timeout extends TimerTask {
    @Override public void run() {
      done.set(true);
      if (callback != null)  callback.run();
    }
  }
}