class ExecutionList {

    public void add(Runnable runnable, Executor executor) {
        // Fail fast on a null.  We throw NPE here because the contract of
        // Executor states that it throws NPE on null listener, so we propagate
        // that contract up into the add method as well.
        if (runnable == null) {
            throw new NullPointerException("Runnable can not be null!");
        }
        if (executor == null) {
            logger.info("Executor for listenablefuture is null, will use default executor!");
            executor = DEFAULT_EXECUTOR;
        }
        // Lock while we check state.  We must maintain the lock while adding the
        // new pair so that another thread can't run the list out from under us.
        // We only add to the list if we have not yet started execution.
        synchronized (this) {
            if (!executed) {
                runnables = new RunnableExecutorPair(runnable, executor, runnables);
                return;
            }
        }
        // Execute the runnable immediately. Because of scheduling this may end up
        // getting called before some of the previously added runnables, but we're
        // OK with that.  If we want to change the contract to guarantee ordering
        // among runnables we'd have to modify the logic here to allow it.
        executeListener(runnable, executor);
    }

    public  ExecutionList();

}