I've been working on a data import process the past couple of days, trying to solve some memory issues (OOMEs). Essential we have a reader (the producer) and a writer (the consumer). The writer part of this scenario operates much slower than the reader part. The reader part is implemented as an iterator, so it only produces enough work for the writer to consume. As this design evolved over time, parallel execution of the writer was added, in an effort to speed up the overall writing process. The coordination of the parallelization is an ExecutorService implementation. With this executor service now in place, the iteration of the reader can operate independently of the writer. Thus, the consumer now starts creating lots of tasks that are then submitted to the executor service, where they queue up. The executor service is not bounded, so it just keeps accepting tasks. This wouldn't be a problem if the number of tasks were small and the memory footprint of those tasks was low, but that is not our situation. Thus, we keep blowing out our Java VM process with OOMEs. We're in the process of fixing this issue, using a bounded concurrent collection to handle the buffering of items between the reader and the executor service and ultimately the writer.