Threading-ThreadPool in Java

Suppose in an application , large number of tasks needs to be completed. It is practically not possible to  do all these tasks with separate threads for each task.Creating large number of threads in a Java process is very difficult for the JVM to manage.The concept ThreadPool in Java is useful in situations involving so many tasks  . A  pool of threads can be used for completing those tasks.The number of threads will be limited in this case.

ThreadPool in Java

Here there are a number of threads in the pool . Once a new task comes , the task is adding to a queue. From the queue that task is taking by any of the threads in the pool. When all threads are busy with tasks , then the new tasks coming is keeping in the queue. Those tasks will be taken by any of the threads  in the pool soon.

ThreadPool in Java example

Here , we are discussing  the concept of thread pool with an example.(Java is providing a ThreadPoolExecutor in concurrent package to manage pool of threads.If we are using that directly , the overburden of creating and managing threads will be gone).

The first class given here is the ThreadPool.java . It is having a LinkedBlockingQueue to keep the incoming tasks. It is having an array of Service objects. The Service object is nothing but a thread object . That also given below as the second code snippet.ThreadPool is starting the threads . Once a new task comes the task is passing to the execute method , where the task is adding to the queue of ThreadPool and notifying all the Service threads. If any of the Service thread is waiting to get a task , the new task is  giving to that Service and it will be executed .

import java.util.concurrent.LinkedBlockingQueue;

public class ThreadPool {
private int poolSize = 0;
private LinkedBlockingQueue queue = null;
private Service[] services = null;

public ThreadPool(int size) {
this.poolSize = size;
services = new Service[size];
this.queue = new LinkedBlockingQueue();
startServices();

}

private void startServices() {
for (int i = 0; i < poolSize; i++) { services[i] = new Service(queue); services[i].start(); } } public void execute(Runnable task) { synchronized (queue) { queue.add(task); queue.notify(); } } }

Now let us see the Service.java. It is nothing but a thread object. The ThreadPool.java class shown above has an array of Service objects. These are threads which can access the same LinkedBlockingQueue of ThreadPool.java.So the Service thread can take the task added in ThreadPool.

import java.util.concurrent.LinkedBlockingQueue;

public class Service extends Thread {
private LinkedBlockingQueue queue = null;
private Runnable task = null;
public Service(LinkedBlockingQueue queue , String name) {
super(name);
this.queue = queue;
}
public void run() {
while (true) {
synchronized (queue) {
while (queue.isEmpty()) {
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
try {
task = (Runnable) queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
task.run();
}
}
}

If there is no task in the queue ,  then the Service thread is waiting on queue.Once a new task comes , Service thread moves out from the wait and takes that task. And then executes the task. Our task is Runnable but we are not executing the task with start() method.Because we are not going to start a new thread for each Runnable ,but executing the task in the current service thread.

Now let us see the main class.The main class is creating a ThreadPool instance with number of Services as 3 .And creating four Runnable tasks.

1)First task is printing multiples of 10 from 0 to 50

2)Second task is printing multiples of 10 from 50 to 100

3)Third task is printing  multiples of 10 from 100 to 150

4)Fourth task is printing multiples of 10 from 150 to 200

Before printing the next number , a  sleep time of 5 seconds is given .It is to see the working correctly.

public class ThreadPoolMain {
public ThreadPoolMain() {

}
  public static void main(String[] args) {

ThreadPool pool = new ThreadPool(3);
Runnable firstTask = new Runnable() {
int number = 0;
public void run() {
while (number < 50) { System.out.println("Thread :" + Thread.currentThread().getName() + ": Number = " + number); number = number + 10; try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Runnable secondTask = new Runnable() { int number = 50; public void run() { while (number < 100) { System.out.println("Thread :" + Thread.currentThread().getName() + ": Number = " + number); number = number + 10; try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Runnable thirdTask = new Runnable() { int number = 100; public void run() { while (number < 150) { System.out.println("Thread :" + Thread.currentThread().getName() + ": Number = " + number); number = number + 10; try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Runnable fourthTask = new Runnable() { int number = 150; public void run() { while (number < 200) { System.out.println("Thread :" + Thread.currentThread().getName() + ": Number = " + number); number = number + 10; try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } }; pool.execute(firstTask); pool.execute(secondTask); pool.execute(thirdTask); pool.execute(fourthTask); } }

Now let us see the output.Here three Service threads are starting.So 3  out of the four tasks will be taken.Once any of the service finishes its task , it takes the remaining task.When queue is empty the threads are waiting. The working can be well understood if we use any Java profiler.( If we are using newer versions of jdk then the bin directory of JDK contains a JVisualVM.exe. if we profile our application with VisualVM , we can see the status of each thread in the pool) .Remember , this application is not exiting itself , because the Service threads are executing for the whole time(because of the while(true) in run() method )

Output

Thread  :Service2: Number = 0

Thread  :Service1: Number = 100

Thread  :Service0: Number = 50

Thread  :Service1: Number = 110

Thread  :Service0: Number = 60

Thread  :Service2: Number = 10

Thread  :Service1: Number = 120

Thread  :Service0: Number = 70

Thread  :Service2: Number = 20

Thread  :Service1: Number = 130

Thread  :Service0: Number = 80

Thread  :Service2: Number = 30

Thread  :Service1: Number = 140

Thread  :Service0: Number = 90

Thread  :Service2: Number = 40

Thread  :Service1: Number = 150

Thread  :Service1: Number = 160

Thread  :Service1: Number = 170

Thread  :Service1: Number = 180

Thread  :Service1: Number = 190

You can change the number of threads  in the main method  and you can see the difference .

See Related Discussions

Threading Basics

Thread Safety in Java

Thread Communication in Java

Thread Priorities in Java

The join() method in Threading

The yield() method in Threading

The sleep() method in threading

Daemon Threads in Java

ThreadPoolExecutor in Java

Thread Dead lock in Java

Thread Live lock in Java

Leave a Reply

Your email address will not be published. Required fields are marked *