@Override
                    public void run() {

                        // Important .. handling thread (main thread) gets to run first.
                        // This is because the collecting process should be run on demand in response to
                        // iterator access. Each result should be dealt with by the handling process before
                        // the collecting process is able to modify any resources that may be requred by
                        // results.

                        try {
                            returnQueue.take();
                        } catch (final InterruptedException e) {
                            //throw new RuntimeException("Error with yield adapter", e);
                            return;
                        }
                        try {
                            try {

                                client.collect(new ResultHandler<T>() {
                                    public T handleResult(final T value)
                                            throws CollectionAbortedException {
                                        try {
                                            T oldValue = iterator.getCurrentValue();
                                            synchronousQueue.put(new ValueMessage(value));
                                            returnQueue.take();  // wait for permission to continue
                                            return oldValue;
                                        } catch (final InterruptedException e) {
                                            // this thread has been aborted
                                            throw new CollectionAbortedException(e);
                                        }
                                    }
                                });

                                synchronousQueue.put(new EndMessage());
                                // Signal no more results to come

                            } catch (final CollectionAbortedException collectionAborted) {
                                if (!(collectionAborted
                                        .getCause() instanceof InterruptedException)) {
                                    // Collect was aborted by client
                                    // This is not sent on thread abort as there is nothing waiting
                                    // to receive it, and the thread will block.
                                    synchronousQueue.put(new AbortedMessage());
                                }
                            }

                        } catch (final InterruptedException e) {
                            // Operation was aborted internally (e.g.  iterator out of scope)
                        }
                    }
This can be manually called by the calling code to force release of
resources at the earliest opportunity.
jphp-runtime/src/php/runtime/util/generator/ThreadedYieldAdapter.java