Isso acontece porque threads não são mágicas. Sempre que for usá-las, existe um custo adicional para gerenciá-las.
O ExecutorService
, por exemplo, tem o seu custo, afinal, ele faz todo o trabalho de gerenciar e coordenar as threads, e isso não vem de graça. Esse custo a mais só se paga em certos casos (depende do tipo de tarefa, da quantidade de threads, e de muitos outros fatores).
O link já indicado em outro comentário dá uma explicação bem detalhada disso.