public ForThread<T> forThread(Consumer<T> consumer) {
    working.incrementAndGet();
    return new ForThread<>() {
      boolean finished = false;

      @Override
      public void accept(T t) {
        if (finished) {
          throw new IllegalStateException("Finished");
        }
        if (done.get() == 0 || !pending.offer(t)) {
          consumer.accept(t);
        }
      }

      @Override
      public void finish() {
        if (!finished) {
          done.incrementAndGet();
          working.decrementAndGet();
          finished = true;
        }
      }

      @Override
      public void drain() {
        T item;
        while ((item = pending.poll()) != null || working.get() > 0) {
          if (item == null) {
            try {
              item = pending.poll(100, TimeUnit.MILLISECONDS);
              if (item == null && working.get() <= 0) {
                break;
              }
            } catch (InterruptedException e) {
              Thread.currentThread().interrupt();
              break;
            }
          }
          if (item != null) {
            consumer.accept(item);
          }
        }
      }

      @Override
      public void close() {
        finish();
        drain();
      }
    };
  }
A handle for each worker thread to offer new items, and drain the remaining ones when done.
planetiler-core/src/main/java/com/onthegomap/planetiler/worker/Distributor.java