Thread Pool

Java Thread pool represents a group of worker threads that are waiting for the job and reused many times. In the case of a thread pool, a group of fixed-size threads is created. A thread from the thread pool is pulled out and assigned a job by the service provider. After completion of the job, the thread is contained in the thread pool again.

Methods of Thread Pool

MethodDescription
newFixedThreadPool(int s)The method creates a thread pool of the fixed size s.
newCachedThreadPool()The method creates a new thread pool that creates the new threads when needed but will still use the previously created thread whenever they are available to use.
newSingleThreadExecutor()The method creates a new thread.

Features of Thread Pool

  • Don’t queue tasks that concurrently wait for results from other tasks. This can lead to a situation of deadlock as described above.

  • 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.

  • 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.

  • 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.

  • You can restrict maximum number of threads that can run in JVM, reducing chances of JVM running out of memory.

  • 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.

  • 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.)

Types of Thread Pool

  • Single Thread Executor : A thread pool with only one thread. So all the submitted tasks will be executed sequentially. Method :
Executors.newSingleThreadExecutor();
  • Cached Thread Pool : A thread pool that creates as many threads it needs to execute the task in parrallel. The old available threads will be reused for the new tasks. If a thread is not used during 60 seconds, it will be terminated and removed from the pool.

Method :

Executors.newCachedThreadPool();
  • Fixed Thread Pool : A thread pool with a fixed number of threads. If a thread is not available for the task, the task is put in queue waiting for an other task to ends.

Method :

Executors.newFixedThreadPool();
  • Scheduled Thread Pool : A thread pool made to schedule future task.

Method :

Executors.newScheduledThreadPool();
  • Single Thread Scheduled Pool : A thread pool with only one thread to schedule future task.

Method :

Executors.newSingleThreadScheduledExecutor();

Advantages of a Thread Pool

Some of the advantages of using thread pool when programming in Java are:

  • Better performance

  • Saves time

  • No need to create a thread again and again

  • Easy to access

  • Real-time usage

Disadvantages of the Thread Pool

Some of the disadvantages of using thread pool when programming are:

  • There is no control over the priority and state of the thread you are working with.

  • There is no stable identity given to the thread, no track can be kept.

  • When there is a high demand for the thread pool, the process may be deleted.

  • The thread pool can not work well when two threads are working in parallel.

  • There are several situations where the application code can be affected by another application code, despite robust application isolation.

Example

// important import statements  

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.text.SimpleDateFormat;


class Tasks implements Runnable {
    private String taskName;

    // constructor of the class Tasks
    public Tasks(String str) {
// initializing the field taskName   
        taskName = str;
    }

    // Printing the task name and then sleeps for 1 sec
// The complete process is getting repeated five times  
    public void run() {
        try {
            for (int j = 0; j <= 5; j++) {
                if (j == 0) {
                    Date dt = new Date();
                    SimpleDateFormat sdf = new SimpleDateFormat("hh : mm : ss");

//prints the initialization time for every task  
                    System.out.println("Initialization time for the task name: " + taskName + " = " + sdf.format(dt));

                } else {
                    Date dt = new Date();
                    SimpleDateFormat sdf = new SimpleDateFormat("hh : mm : ss");

// prints the execution time for every task  
                    System.out.println("Time of execution for the task name: " + taskName + " = " + sdf.format(dt));

                }

// 1000ms = 1 sec  
                Thread.sleep(1000);
            }

            System.out.println(taskName + " is complete.");
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        }
    }
}

class ThreadPoolExample {
    // Maximum number of threads in the thread pool
    static final int MAX_TH = 3;

    // main method
    public static void main(String argvs[]) {
// Creating five new tasks  
        Runnable rb1 = new Tasks("task 1");
        Runnable rb2 = new Tasks("task 2");
        Runnable rb3 = new Tasks("task 3");
        Runnable rb4 = new Tasks("task 4");
        Runnable rb5 = new Tasks("task 5");

// creating a thread pool with MAX_TH number of  
// threads size the pool size is fixed  
        ExecutorService pl = Executors.newFixedThreadPool(MAX_TH);

// passes the Task objects to the pool to execute (Step 3)  
        pl.execute(rb1);
        pl.execute(rb2);
        pl.execute(rb3);
        pl.execute(rb4);
        pl.execute(rb5);

// pool is shutdown  
        pl.shutdown();
    }
} 

Output

Initialization time for the task name: task 1 = 06 : 13 : 02
Initialization time for the task name: task 2 = 06 : 13 : 02
Initialization time for the task name: task 3 = 06 : 13 : 02
...
Time of execution for the task name: task 1 = 06 : 13 : 08
Time of execution for the task name: task 2 = 06 : 13 : 08
Time of execution for the task name: task 3 = 06 : 13 : 08
task 2 is complete.
Initialization time for the task name: task 4 = 06 : 13 : 09
task 1 is complete.
Initialization time for the task name: task 5 = 06 : 13 : 09
task 3 is complete.
Time of execution for the task name: task 4 = 06 : 13 : 10
Time of execution for the task name: task 5 = 06 : 13 : 10
...
Time of execution for the task name: task 5 = 06 : 13 : 14
task 4 is complete.
task 5 is complete.

In the above example when one wants to execute 50 tasks but is not willing to create 50 threads. In such a case, one can create a pool of 10 threads. Thus, 10 out of 50 tasks are assigned, and the rest are put in the queue. Whenever any thread out of 10 threads becomes idle, it picks up the 11th task. The other pending tasks are treated the same way.

core java programming multithreading concurrency

Subscribe For More Content