In simple concurrent applications, we execute concurrent tasks using the Runnable interface and the Thread class. We create and manage the threads and control their execution. We can't follow this approach in big concurrent applications because it can create many problems. For these cases, the Java concurrency API has introduced the Executor framework. In this chapter, we presented the basic characteristics and components that form this framework. First of all, we explored the Executor interface, which defines the basic method to send a Runnable task to an executor. This interface has a subinterface, the ExecutorService interface, which includes methods to send to the executor tasks that return a result (these tasks implement the Callable interface, as we will see in Chapter 5, Getting Data from Tasks - Callable and Future Interfaces), and a list of tasks.
The ThreadPoolExecutor...