class ListenerWrapper implements Consumer<CalculationResults> {

  @Override
  public void accept(CalculationResults result) {
    CalculationResults nextResult;

    // Multiple calculation threads can try to acquire this lock at the same time.
    // The thread which acquires the lock will set the executing flag and proceed into
    // the body of the method.
    // If another thread acquires the lock while the first thread is executing it will
    // add an item to the queue and return.
    // The lock also ensures the state of the executing flag and the queue are visible
    // to any thread acquiring the lock.
    lock.lock();
    try {
      if (executing) {
        // Another thread is already invoking the listener. Add the result to
        // the queue and return. The other thread will ensure the queued results
        // are delivered.
        queue.add(result);
        return;
      } else {
        // There is no thread invoking the listener. Set the executing flag to
        // ensure no other thread passes this point and invoke the listener.
        executing = true;
        nextResult = result;
      }
    } finally {
      lock.unlock();
    }

    // The logic in the block above guarantees that there will never be more than one thread in the
    // rest of the method below this point.

    // Loop until the nextResult and all the results from the queue have been delivered
    for (;;) {
      // The logic above means this lock is never contended; the executing flag means
      // only one thread will ever be in this loop at any given time.
      // This lock is required to ensure any state changes in the listener are visible to all threads
      listenerLock.lock();
      try {
        // Invoke the listener while not protected by lock. This allows other threads
        // to queue results while this thread is delivering them to the listener.
        for (CalculationResult cell : nextResult.getCells()) {
          listener.resultReceived(nextResult.getTarget(), cell);
        }
      } catch (RuntimeException e) {
        log.warn("Exception invoking listener.resultReceived", e);
      } finally {
        listenerLock.unlock();
      }

      // The following code must be executed whilst holding the lock to guarantee any changes
      // to the executing flag and to the state of the queue are visible to all threads
      lock.lock();
      try {
        if (++tasksReceived == tasksExpected) {
          // The expected number of results have been received, inform the listener.
          // The listener lock must be acquired to ensure any state changes in the listener are
          // visible to all threads
          listenerLock.lock();
          try {
            listener.calculationsComplete();
          } catch (RuntimeException e) {
            log.warn("Exception invoking listener.calculationsComplete", e);
          } finally {
            listenerLock.unlock();
          }
          return;
        } else if (queue.isEmpty()) {
          // There are no more results to deliver. Unset the executing flag and return.
          // This allows the next calling thread to deliver results.
          executing = false;
          return;
        } else {
          // There are results on the queue. This means another thread called accept(),
          // added a result to the queue and returned while this thread was invoking the listener.
          // This thread must deliver the results from the queue.
          nextResult = queue.remove();
        }
      } finally {
        lock.unlock();
      }
    }
  }

    ListenerWrapper(CalculationListener listener, int tasksExpected, List<CalculationTarget> targets, List<Column> columns);

}