Header Ads Widget

Responsive Advertisement

Thread pool executor service

 

package com.kartik.thread.pool;

 

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

/**

 *

 * @author kmandal

 *

 *

 */

public class TestThreadPool {

 // Maximum number of threads in thread pool

    static final int MAX_T = 3;             

 

    public static void main(String[] args)

    {

        // creates five tasks

     Task r1 = new Task("task 1",4);

     Task r2 = new Task("task 2",3);

        Runnable r3 = new Task("task 3",6);

        Runnable r4 = new Task("task 4",9);

        Runnable r5 = new Task("task 5",18);

        Runnable r6 = new Task("task 6",4);

        Runnable r7 = new Task("task 7",3);

        Runnable r8 = new Task("task 8",6);

        Runnable r9 = new Task("task 9",9);

        Runnable r10 = new Task("task 10",4);

        Runnable r11 = new Task("task 11",3);

        Runnable r12 = new Task("task 12",6);

        Runnable r13 = new Task("task 13",9);

        Runnable r14 = new Task("task 14",4);

        Runnable r15 = new Task("task 15",3);

        Runnable r16 = new Task("task 16",6);

        Runnable r17 = new Task("task 17",9);

         

        // creates a thread pool with MAX_T no. of 

        // threads as the fixed pool size(Step 2)

        ExecutorService pool = Executors.newFixedThreadPool(MAX_T);  

        

        // passes the Task objects to the pool to execute (Step 3)

        pool.execute(r1);

        pool.execute(r2);

        pool.execute(r3);

        pool.execute(r4);

        pool.execute(r5);

        pool.execute(r6);

        pool.execute(r7);

        pool.execute(r8);

        pool.execute(r9);

        pool.execute(r10);

        pool.execute(r11);

        pool.execute(r12);

        pool.execute(r13);

        pool.execute(r14);

        pool.execute(r15);

        pool.execute(r16);

        pool.execute(r17);

         

        // pool shutdown ( Step 4)

        pool.shutdown();    

    }

}

 

package com.kartik.thread.pool;

//Java program to illustrate 

//ThreadPool

import java.text.SimpleDateFormat; 

import java.util.Date;

 

//Task class to be executed (Step 1)

public class Task implements Runnable   

{

 private String name;

 private int data;

  

 public Task(String s,int d)

 {

     name = s;

     data=d;

 }

  

 // Prints task name and sleeps for 1s

 // This Whole process is repeated 5 times

 public void run()

 {

     try

     {

          

        System.out.println("Executing Time for task name - "+name +" and factorial data = " +factorial(data)+" thread name "+Thread.currentThread().getName());

        Thread.sleep(100);

        System.out.println(name+" complete");

     }

      

     catch(InterruptedException e)

     {

         e.printStackTrace();

     }

 }

 

 

//method to find factorial of given number

 static long factorial(long n)

 {

     if (n == 0)

       return 1;

      

     return n*factorial(n-1);

 }

}

 

TestThreadPool example effectively demonstrates the use of a thread pool in Java. Let’s break down some of the concepts you're asking about and explain why a thread pool offers better performance compared to creating new threads each time.

Thread Life Cycle in Java

A thread in Java generally goes through three stages:

  1. Creation: This involves notifying the operating system (OS) to create a new thread. The OS allocates resources, such as a stack, for the thread.
  2. Execution: The thread executes its run() method. This is where the actual work of the thread is done.
  3. Termination: After the thread finishes executing its run() method, it is terminated. The OS then reclaims the resources allocated to it.

Thread Pool Basics

  • Thread Pool: A thread pool is a group of pre-created threads that are kept alive and reused to execute multiple tasks. When a new task is submitted, a thread from the pool is assigned to execute the task. After completing the task, the thread goes back to the pool instead of being destroyed, so it can be reused for future tasks.
  • Worker Threads: These are the threads that belong to the thread pool. Unlike regular threads that are created, run, and then destroyed, worker threads are kept alive and can execute multiple tasks throughout their lifecycle. This is why they are more efficient—they avoid the overhead associated with thread creation and destruction.

Why Thread Pools Improve Performance

  1. Reduced Overhead: The most significant advantage of using a thread pool is the reduction in overhead for creating and destroying threads. In scenarios where tasks are short-lived or where many tasks need to be executed, constantly creating and destroying threads can consume significant CPU and memory resources.
  2. Efficient Resource Management: Thread pools manage resources more efficiently by limiting the number of threads that can run concurrently. This prevents the system from being overwhelmed by too many threads.
  3. Reusability: Threads in a pool are reused to execute multiple tasks. After a thread completes a task, it does not terminate but instead goes back to the pool to be reused for the next task.

Example: Understanding the Code

code example demonstrates these principles:

java

// Creates a thread pool with a maximum of 3 threads

ExecutorService pool = Executors.newFixedThreadPool(MAX_T);

 

// Submits multiple tasks to the thread pool

pool.execute(r1);

pool.execute(r2);

...

pool.execute(r17);

 

// Shuts down the pool after all tasks have been submitted

pool.shutdown();

 

Key Points:

  • Thread Reuse: The same worker threads in the pool are reused for different tasks. For example, a thread that completes task 1 can be immediately reused to execute task 4 without being destroyed.
  • Concurrency Control: The thread pool ensures that only MAX_T (3 in this case) threads are active at any time. If more tasks are submitted than there are available threads, the tasks are queued and will be executed as threads become available.

Worker Threads vs. Regular Threads

  • Worker Threads: Exist separately from the tasks they execute. They remain alive in the pool and can execute multiple tasks over time.
  • Regular Threads: Are created for a specific task and usually destroyed after the task is completed.

 

This code defines a Task class that implements the Runnable interface. Each task calculates the factorial of a given number and prints out some details, including the name of the task and the thread it is running on. This setup is useful for executing tasks concurrently using a thread pool.

Here’s a brief explanation of the components:

1. Class Definition and Constructor

  • The class Task implements Runnable, meaning it can be executed by a thread.
  • The constructor accepts two parameters:
    • String s: The name of the task.
    • int d: The data on which the task will operate (in this case, the number for which the factorial is to be calculated).

2. run() Method

  • This is the method that will be executed when the thread runs. It performs the following:
    • Prints out the task's name, the factorial of the number, and the name of the current thread.
    • Sleeps for 100 milliseconds to simulate some work being done.
    • Prints a completion message after waking up.

3. factorial() Method

  • A static method that calculates the factorial of a given number using recursion.

Sample Output

When run, the run() method of the Task class might produce output similar to the following:

plaintext

Executing Time for task name - Task1 and factorial data = 120 thread name pool-1-thread-1

Task1 complete

Executing Time for task name - Task2 and factorial data = 720 thread name pool-1-thread-2

Task2 complete

 

How to Use with a Thread Pool

To make use of this Task class, you can create a thread pool using Java's ExecutorService. Here’s a basic example of how to set it up:

java

package com.kartik.thread.pool;

 

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

 

public class ThreadPoolExample {

 

    public static void main(String[] args) {

        // Creating a thread pool with 3 threads

        ExecutorService executor = Executors.newFixedThreadPool(3);

       

        // Submitting tasks to the thread pool

        for (int i = 1; i <= 5; i++) {

            Task task = new Task("Task" + i, i + 4);

            executor.execute(task);

        }

 

        // Shutting down the executor service

        executor.shutdown();

    }

}

 

Explanation of the Thread Pool Example:

  1. ExecutorService: Manages a pool of threads, executing tasks concurrently.
    • Executors.newFixedThreadPool(3): Creates a thread pool with 3 threads.
  2. Submitting Tasks: The loop creates and submits 5 tasks to the thread pool. Each task calculates the factorial of a number and prints out the result.
  3. Shutdown: Once all tasks are submitted, executor.shutdown() is called to stop accepting new tasks and let the existing ones finish.

Running the Example

When you run ThreadPoolExample, the tasks will execute concurrently, each on a separate thread from the pool. The number of concurrent threads will not exceed the size of the pool (3 in this case), so some tasks may wait for others to finish before starting.

This setup is commonly used for managing multiple tasks that can be processed in parallel, especially in scenarios involving I/O operations, long computations, or tasks that are independent of each other.

 

 

When to Use Thread Pools

Thread pools are ideal when:

  • You have a large number of short-lived tasks.
  • You need to control the number of concurrent threads.
  • You want to avoid the overhead of creating and destroying threads repeatedly.

By using a thread pool, you achieve better performance, especially in environments where tasks are numerous and frequent. 

Executor Service
Executor Service




Thread pool
Thread pool





Post a Comment

0 Comments