/**
   * Adds target requirements to the graph. The requirements are queued and the call returns;
   * construction of the graph will happen on a background thread (if additional threads is
   * non-zero), or when the call to {@link #getDependencyGraph} is made. If it was not possible to
   * satisfy one or more requirements that must be checked after graph construction is complete.
   *
   * <p>The caller must ensure that the same requirement is not passed multiple times to the
   * builder. Depending on scheduling and memory availability, the cases may be identified and
   * coalesced (by {@link GraphBuildingContext#resolveRequirement}) into a single logical operation.
   * Alternatively the resolutions may run to completion to include terminal outputs in the result.
   * If the function library contains an ambiguity or other aspect that means the resolved value
   * specification could differ this will result in an invalid dependency graph.
   *
   * @param requirements requirements to add, not null and not containing nulls.
   */
  public void addTarget(final Collection<ValueRequirement> requirements) {
    ArgumentChecker.noNulls(requirements, "requirements");

    // Check that the market data availability provider, the function resolver and the calc config
    // name are non-null
    checkInjectedInputs();

    // Use the context as a build complete lock so that housekeeping thread cannot observe a "built"
    // state within this atomic block of work
    synchronized (getContext()) {
      for (final ValueRequirement requirement : requirements) {
        addTargetImpl(requirement);
      }
    }
    // If the run-queue was empty, we may not have started enough threads, so double check
    startBackgroundConstructionJob();
  }
  /**
   * Adds a target requirement to the graph. The requirement is queued and the call returns;
   * construction of the graph will happen on a background thread (if additional threads is
   * non-zero), or when the call to {@link #getDependencyGraph} is made. If it was not possible to
   * satisfy the requirement that must be checked after graph construction is complete.
   *
   * <p>The caller must ensure that the same requirement is not passed multiple times to the
   * builder. Depending on scheduling and memory availability, the cases may be identified and
   * coalesced (by {@link GraphBuildingContext#resolveRequirement}) into a single logical operation.
   * Alternatively the resolutions may run to completion to include terminal outputs in the result.
   * If the function library contains an ambiguity or other aspect that means the resolved value
   * specification could differ this will result in an invalid dependency graph.
   *
   * @param requirement requirement to add, not null
   */
  public void addTarget(final ValueRequirement requirement) {
    ArgumentChecker.notNull(requirement, "requirement");

    // Check that the market data availability provider, the function resolver and the calc config
    // name are non-null
    checkInjectedInputs();

    // Use the context as a build complete lock so that housekeeping thread cannot observe a "built"
    // state within this atomic block of work
    synchronized (getContext()) {
      // Add the value requirement to the graph (actually adds a suitable resolution task to the run
      // queue)
      addTargetImpl(requirement);
    }
    // If the run-queue was empty, we won't have started a thread, so double check
    startBackgroundConstructionJob();
  }
  /**
   * Add a task to the run queue, increment the count of scheduled steps, and start/wake up a
   * background thread if the run queue was empty, as this indicates that there are probably no
   * active threads at this precise moment.
   *
   * @param runnable the task to add to the run queue
   */
  protected void addToRunQueue(final ContextRunnable runnable) {

    // Check if the run queue is empty
    final boolean dontSpawn = _runQueue.isEmpty();

    // Increment the number of scheduled steps
    _scheduledSteps.incrementAndGet();

    // Actually add the task to this DependencyGraphBuilder's run queue
    _runQueue.add(runnable);

    // Don't start construction jobs if the queue is empty or a sequential piece of work bounces
    // between two threads (i.e. there
    // is already a background thread that is running the caller which can then execute the task it
    // has just put into the run
    // queue). The moment the queue is non-empty, start a job if possible.
    if (!dontSpawn) {
      startBackgroundConstructionJob();
    }
  }