Join Ketkee Aryamane for an in-depth discussion in this video Features of the Executor framework and thread pools, part of Java EE: Concurrency and Multithreading.
- Let's understand the features of the Executor Framework now. The first and the most vital feature is that it decouples thread creation and management logic from the application business logic. This means that now as a developer, you only have to focus on your business logic, rather than getting into the hassles of thread creation and management. In a Java Standalone application, we know that everything starts off with the main method. That's the place where we created the thread instances, and we started them off for the execution. So there is a thread which is going to submit the task for you, and there's a thread which is going to do the job for you.
The framework provides a very clear demarcation, and a smooth coordination between the thread submitting the task, and the thread executing the job. Additionally, the framework gives you options to make a clean shutdown of all the tasks running in your system. Let's say if the task wants to return something, the framework will allow you to have a return value of the task. You can also check that out in the thread which submitted that task. The requirement of scheduling certain jobs at regular intervals or with fixed delays can be very easily met with the Executor Framework.
Lastly, the framework automatically creates thread pools, which helps you spawn threads for your jobs of the application. But what is a thread pool? OK, let's understand that as well. Let's say you have an application, a banking website, which has got millions of users, so millions of bank accounts. The requirement is that we want to generate a transaction report for every bank account. Now this is a requirement where the user interference is not necessary, so we decided to spawn it in a thread. But when you have millions of bank accounts, you may want to create one thread per bank account.
Oh, no, no, but if you do that, you will quickly exceed the maximum number of threads that can be created for the underlying platform, and eventually, your system is going to come crashing down. Doesn't work. Standalone applications, or enterprise applications which deal with threads often have this very common requirement to handle a large number of clients. And if you are going to spawn one thread per client, it is going to incur excessive processing overhead. Allocating and de-allocating memory resources is a very costly business for a thread.
So we have a thread pool. A thread pool is a logical pool with a fixed number of threads. Each thread is going to be given a job to do. Once that job is over, and let's say if the thread is terminated, then in its place, a new thread will be created. However, at any point in time, the application will always have a fixed number of threads. So we are reusing threads, and re-usability is definitely one of the most important aspects of software development. So creating thread pools is definitely a better way to scale the concurrent application's performance.
Thread pools do a lot of stuff for you. The first is they reduce per-task invocation overhead. Second, manage resources efficiently. Thread pools are often used with connection pooling, where every thread maintains an open connection to the database, that way you do not end up creating too many database objects as well, which may put your system under unnecessary stress. They also help to degrade the applications gracefully. For example, in a web application every incoming request is always managed by a thread, but you may have millions of incoming requests.
You cannot possibly spawn a thread for every request, a new thread, right? That'll become very difficult, and eventually, your application is going to stop responding to all the requests. But when you create a thread pool, you always have a limited number of threads. So even if the requests keep coming in at a faster pace, the threads are going to make sure that the requests are handled according to the sustainability of the system. Now Java Executor framework allows you to create many kinds of thread pools.
You don't have to do anything for it, the framework will do this job for you. Now the last point that I want to mention here, is what about the thread pool size? How many threads do you think should reside in the pool? Now that is decided based on a lot of factors. For example, how many codes do you have in your CPU? What kind of tasks are I/O intensive tasks? What kind of tasks are compute intensive tasks? And so on and so forth. So there are a lot of factors, and the framework does all of this job for you, so you don't have to worry about it.
- What is concurrency?
- Processes and threads in Java SE
- Java EE concurrency APIs
- Working with the ManagedExecutorService, ManagedScheduledExecutorService, ManagedThreadFactory, and ContextService APIs
- Defining data access object (DAO) classes
- Adding methods to DAO classes
- Writing REST classes
- Creating custom thread factories
- Creating contextual proxies
- JTA transactions and concurrency