Now that I actually see it in action, I wonder if we could use ForkJoinPool.commonPool() instead :)

ThreadPoolExecutor is very finicky, if you set a queue size and you don't ever fill it, you'll end up using a single thread. And if you do fill the queue, the rejection policy used by DefaultExecutorFactory is CallerRunsPolicy, which means you won't generate new tasks for a while. All in all, I think a ForkJoinPool should be much better, and we already use one when we don't have size-based eviction.