This is not so much the futures that come back, this is your problem. The problem is that for every Runnable you submit, the ExecutorService will save them so that it can handle later. Each time you call the submit method using Runnable (or Future), the ExecutorService will push that runnable to the work queue. Runnable will sit there until Thread can select Runnable from the queue (later). If all worker threads are busy, then the ExecutorService will simply put the runnable in the specified queue.
So your problem is that you have only one thread trying to pull out a queue that is endlessly added to another thread. Adding it is much faster than a worker thread can handle each Runnable.
Edit: the code sample that I gave as nos did not execute, in fact, throws a RejectedExecutionException, so the throttling mechanism would have to be slightly different if you chose.
As for the best solution, as I mentioned in my comment; If you expect to fill out the ExecutorService so that the worker threads cannot keep up with the queue, you can serialize and deserialize the requests as they arrive (by building my own ThreadPoolExecutor), but I would make sure such a case is absolutely necessary.
Keep in mind that after the work has been done, they will be discarded and garbage collected. Therefore, if you make one Future per second, and it is fulfilled in a second, then the Future will be deleted and you will not have a memory problem. But if you make one Future second, and streams make the Future every 3 seconds, it will draw and render.
Edit: I have profiled a bunch of the program you are working in, and that is the problem. FutureTask created by ExecutorService sits in the work queue until the workflow selects it
Class Name | Shallow Heap | Retained Heap | Percentage ------------------------------------------------------------------------------------------------------------ java.util.concurrent.ThreadPoolExecutor @ 0x78513c5a0 | 104 | 2,051,298,872 | 99.99% |- java.util.concurrent.LinkedBlockingQueue @ 0x785140598 | 80 | 2,051,298,216 | 99.99% | |- java.util.concurrent.LinkedBlockingQueue$Node @ 0x785142dd8| 32 | 2,051,297,696 | 99.99% ------------------------------------------------------------------------------------------------------------
Heap analysis goes a bit, there are a lot of LinkedBlockingQueue $ Node, as you can imagine