Creating a thread manually is fine when we want a single thread to do some work, perhaps a long-lived thread or a very simple one-off task that would run concurrently. However, when we want to run many different tasks concurrently while sharing limited CPU time, track the process of tasks in an easy way, or simply want to abstract how each task will run, we can turn to ExecutorService; this is commonly called an executor as well. An executor is part of the standard Java library.
An executor is a more generic interface with a single run() function. ExecutorService is a more fully featured interface and is usually the abstraction used. It is common for people to use the term executor when referring to either.
ExecutorService is simply an object that executes submitted tasks while allowing us to control the life cycle of the executor, that is, rejecting new tasks or interrupting...