public ResolvedValueProducer declareTaskProducing(
     final ValueSpecification valueSpecification,
     final ResolveTask task,
     final ResolvedValueProducer producer) {
   do {
     final MapEx<ResolveTask, ResolvedValueProducer> tasks =
         getBuilder().getOrCreateTasks(valueSpecification);
     ResolvedValueProducer result = null;
     if (tasks != null) {
       ResolvedValueProducer discard = null;
       synchronized (tasks) {
         if (!tasks.isEmpty()) {
           if (tasks.containsKey(null)) {
             continue;
           }
           final Map.Entry<ResolveTask, ResolvedValueProducer> resolveTask =
               tasks.getHashEntry(task);
           if (resolveTask != null) {
             if (resolveTask.getKey() == task) {
               // Replace an earlier attempt from this task with the new producer
               discard = resolveTask.getValue();
               producer.addRef(); // The caller already holds an open reference
               resolveTask.setValue(producer);
               result = producer;
             } else {
               // An equivalent task is doing the work
               result = resolveTask.getValue();
             }
             result
                 .addRef(); // Either the caller holds an open reference on the producer, or we've
                            // got the task lock
           }
         }
         if (result == null) {
           final ResolvedValue value = getBuilder().getResolvedValue(valueSpecification);
           if (value != null) {
             result = new SingleResolvedValueProducer(task.getValueRequirement(), value);
           }
         }
         if (result == null) {
           // No matching tasks
           producer.addRef(); // Caller already holds open reference
           tasks.put(task, producer);
           result = producer;
           result.addRef(); // Caller already holds open reference (this is the producer)
         }
       }
       if (discard != null) {
         discard.release(this);
       }
     } else {
       final ResolvedValue value = getBuilder().getResolvedValue(valueSpecification);
       if (value != null) {
         result = new SingleResolvedValueProducer(task.getValueRequirement(), value);
       }
     }
     return result;
   } while (true);
 }
 public void discardTask(final ResolveTask task) {
   // TODO: Could we post "discardTask" tasks to a queue and have them done in batches by a
   // ContextRunnable?
   do {
     final Map<ResolveTask, ResolveTask> tasks = getBuilder().getTasks(task.getValueRequirement());
     if (tasks == null) {
       return;
     }
     synchronized (tasks) {
       if (tasks.containsKey(null)) {
         continue;
       }
       final int rc = task.getRefCount();
       if (rc == 0) {
         // Not referenced by us by definition
         return;
       }
       if (rc != 1) {
         if (!task.isFinished()) {
           // Can't discard this -- something might be waiting on a result from it??
           return;
         }
       }
       final ResolveTask removed = tasks.remove(task);
       if (removed == null) {
         // Task has already been discarded
         return;
       }
       if (removed != task) {
         // Task has already been discarded and replaced by an equivalent; don't discard that
         tasks.put(removed, removed);
         return;
       }
     }
     task.release(this);
     getBuilder().decrementActiveResolveTasks();
   } while (true);
 }