What is thread pool in java with example

Thread Pools in Java

Server Programs such as database and web servers repeatedly execute requests from multiple clients and these are oriented around processing a large number of short tasks. An approach for building a server application would be to create a new thread each time a request arrives and service this new request in the newly created thread. While this approach seems simple to implement, it has significant disadvantages. A server that creates a new thread for every request would spend more time and consume more system resources in creating and destroying threads than processing actual requests.

Since active threads consume system resources, a JVM creating too many threads at the same time can cause the system to run out of memory. This necessitates the need to limit the number of threads being created.

What is ThreadPool in Java?

A thread pool reuses previously created threads to execute current tasks and offers a solution to the problem of thread cycle overhead and resource thrashing. Since the thread is already existing when the request arrives, the delay introduced by thread creation is eliminated, making the application more responsive.

  • Java provides the Executor framework which is centered around the Executor interface, its sub-interface –ExecutorService and the class-ThreadPoolExecutor, which implements both of these interfaces. By using the executor, one only has to implement the Runnable objects and send them to the executor to execute.
  • They allow you to take advantage of threading, but focus on the tasks that you want the thread to perform, instead of thread mechanics.
  • To use thread pools, we first create a object of ExecutorService and pass a set of tasks to it. ThreadPoolExecutor class allows to set the core and maximum pool size.The runnables that are run by a particular thread are executed sequentially.

TP Init

Thread Pool Initialization with size = 3 threads. Task Queue = 5 Runnable Objects

Executor Thread Pool Methods

Method Description newFixedThreadPool(int) Creates a fixed size thread pool. newCachedThreadPool() Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available newSingleThreadExecutor() Creates a single thread.

In case of a fixed thread pool, if all threads are being currently run by the executor then the pending tasks are placed in a queue and are executed when a thread becomes idle.

Thread Pool Example

In the following tutorial, we will look at a basic example of thread pool executor- FixedThreadPool.

Steps to be followed

1. Create a task(Runnable Object) to execute 2. Create Executor Pool using Executors 3. Pass tasks to Executor Pool 4. Shutdown the Executor Pool

+ » task name — » + name + » line number32 index31 alt1″> //prints the initialization time for every task

Sample Execution

Output: Initialization Time for task name - task 2 = 02:32:56 Initialization Time for task name - task 1 = 02:32:56 Initialization Time for task name - task 3 = 02:32:56 Executing Time for task name - task 1 = 02:32:57 Executing Time for task name - task 2 = 02:32:57 Executing Time for task name - task 3 = 02:32:57 Executing Time for task name - task 1 = 02:32:58 Executing Time for task name - task 2 = 02:32:58 Executing Time for task name - task 3 = 02:32:58 Executing Time for task name - task 1 = 02:32:59 Executing Time for task name - task 2 = 02:32:59 Executing Time for task name - task 3 = 02:32:59 Executing Time for task name - task 1 = 02:33:00 Executing Time for task name - task 3 = 02:33:00 Executing Time for task name - task 2 = 02:33:00 Executing Time for task name - task 2 = 02:33:01 Executing Time for task name - task 1 = 02:33:01 Executing Time for task name - task 3 = 02:33:01 task 2 complete task 1 complete task 3 complete Initialization Time for task name - task 5 = 02:33:02 Initialization Time for task name - task 4 = 02:33:02 Executing Time for task name - task 4 = 02:33:03 Executing Time for task name - task 5 = 02:33:03 Executing Time for task name - task 5 = 02:33:04 Executing Time for task name - task 4 = 02:33:04 Executing Time for task name - task 4 = 02:33:05 Executing Time for task name - task 5 = 02:33:05 Executing Time for task name - task 5 = 02:33:06 Executing Time for task name - task 4 = 02:33:06 Executing Time for task name - task 5 = 02:33:07 Executing Time for task name - task 4 = 02:33:07 task 5 complete task 4 complete

As seen in the execution of the program, the task 4 or task 5 are executed only when a thread in the pool becomes idle. Until then, the extra tasks are placed in a queue.

TP Exec 1

Thread Pool executing first three tasks

TP Exec 2

Thread Pool executing task 4 and 5

One of the main advantages of using this approach is when you want to process 100 requests at a time, but do not want to create 100 Threads for the same, so as to reduce JVM overload. You can use this approach to create a ThreadPool of 10 Threads and you can submit 100 requests to this ThreadPool. ThreadPool will create maximum of 10 threads to process 10 requests at a time. After process completion of any single Thread, ThreadPool will internally allocate the 11th request to this Thread and will keep on doing the same to all the remaining requests.

Risks in using Thread Pools

    1. Deadlock : While deadlock can occur in any multi-threaded program, thread pools introduce another case of deadlock, one in which all the executing threads are waiting for the results from the blocked threads waiting in the queue due to the unavailability of threads for execution.
    2. Thread Leakage :Thread Leakage occurs if a thread is removed from the pool to execute a task but not returned to it when the task completed. As an example, if the thread throws an exception and pool class does not catch this exception, then the thread will simply exit, reducing the size of the thread pool by one. If this repeats many times, then the pool would eventually become empty and no threads would be available to execute other requests.
    3. Resource Thrashing :If the thread pool size is very large then time is wasted in context switching between threads. Having more threads than the optimal number may cause starvation problem leading to resource thrashing as explained.

Important Points

    1. Don’t queue tasks that concurrently wait for results from other tasks. This can lead to a situation of deadlock as described above.
    2. Be careful while using threads for a long lived operation. It might result in the thread waiting forever and would eventually lead to resource leakage.
    3. The Thread Pool has to be ended explicitly at the end. If this is not done, then the program goes on executing and never ends. Call shutdown() on the pool to end the executor. If you try to send another task to the executor after shutdown, it will throw a RejectedExecutionException.
    4. One needs to understand the tasks to effectively tune the thread pool. If the tasks are very contrasting then it makes sense to use different thread pools for different types of tasks so as to tune them properly.
    5. You can restrict maximum number of threads that can run in JVM, reducing chances of JVM running out of memory.
    6. If you need to implement your loop to create new threads for processing, using ThreadPool will help to process faster, as ThreadPool does not create new Threads after it reached it’s max limit.
    7. After completion of Thread Processing, ThreadPool can use the same Thread to do another process(so saving the time and resources to create another Thread.)

Tuning Thread Pool

  • The optimum size of the thread pool depends on the number of processors available and the nature of the tasks. On a N processor system for a queue of only computation type processes, a maximum thread pool size of N or N+1 will achieve the maximum efficiency.But tasks may wait for I/O and in such a case we take into account the ratio of waiting time(W) and service time(S) for a request; resulting in a maximum pool size of N*(1+ W/S) for maximum efficiency.

This article is contributed by Abhishek. If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.

Источник

Thread Pools

Most of the executor implementations in java.util.concurrent use thread pools, which consist of worker threads. This kind of thread exists separately from the Runnable and Callable tasks it executes and is often used to execute multiple tasks.

Using worker threads minimizes the overhead due to thread creation. Thread objects use a significant amount of memory, and in a large-scale application, allocating and deallocating many thread objects creates a significant memory management overhead.

One common type of thread pool is the fixed thread pool. This type of pool always has a specified number of threads running; if a thread is somehow terminated while it is still in use, it is automatically replaced with a new thread. Tasks are submitted to the pool via an internal queue, which holds extra tasks whenever there are more active tasks than threads.

An important advantage of the fixed thread pool is that applications using it degrade gracefully. To understand this, consider a web server application where each HTTP request is handled by a separate thread. If the application simply creates a new thread for every new HTTP request, and the system receives more requests than it can handle immediately, the application will suddenly stop responding to all requests when the overhead of all those threads exceed the capacity of the system. With a limit on the number of the threads that can be created, the application will not be servicing HTTP requests as quickly as they come in, but it will be servicing them as quickly as the system can sustain.

A simple way to create an executor that uses a fixed thread pool is to invoke the newFixedThreadPool factory method in java.util.concurrent.Executors This class also provides the following factory methods:

  • The newCachedThreadPool method creates an executor with an expandable thread pool. This executor is suitable for applications that launch many short-lived tasks.
  • The newSingleThreadExecutor method creates an executor that executes a single task at a time.
  • Several factory methods are ScheduledExecutorService versions of the above executors.

If none of the executors provided by the above factory methods meet your needs, constructing instances of java.util.concurrent.ThreadPoolExecutor or java.util.concurrent.ScheduledThreadPoolExecutor will give you additional options.

Источник

Читайте также:  Pyside6 qt designer python
Оцените статью