Tech Master Tutorials
Email Facebook Google LinkedIn Pinterest Twitter
Home Java Java 8 Java Interview Questions Java Programming

Java Thread Pools


In case of large scale applications, having a separate thread management component abstracts the complexity and makes it easy to manage the threads. Java provides its own thread management constructs like executors, executor services, thread pools callable and future classes.
To know more details go through : Java Concurrency Framework

In Java concurrency model, Executers are used to create and manage the threads. We can pass Runnable or Callable tasks to the executors that can be executed as part of the Threads.
Creating threads using Runnable is explained in the section Creating Threads in Java.


Below is the example of running a Thread by passing a Runnable to the Executor. In the below example, Runnable is passed to an ExecutorService which in turn creates and manages the Thread execution part. Here we have created ExecutorService using Executors class with a SingleThread Execution capability.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecuterRunnable implements Runnable{

	@Override
	public void run() {
		System.out.println("Thread running ....");
		for (int i = 0; i < 5; i++) {
			System.out.println(i);
		}
	}
	
	public static void main(String[] args) {
		ExecuterRunnable runnableObj=new ExecuterRunnable();
		ExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        executor.execute(runnableObj);
	}

}

We can also create a thread pool as part of the executor and then pass the task to the executor that will be handled by one of the threads in thread pool.

Thread Pools:
Thread pools are used mostly in all the executor implementations. These thread pools consists of worker threads. Worker threads are not the Runnable or Callable tasks but are threads that are used to execute Runnable or Callable tasks.

In the below example, Callable instance has been created and passed to ExecutorService which operates upon a fixed thread pool.
5 has been passed as the argument to newFixedThreadPool() to notify the number of threads that will be managed by the fixed thread pool.
ThreadPool will have 5 threads to be used by the executor service. If any of the thread goes down then it will create a thread to make the count 5. There will always be 5 threads as part of the thread pool.

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class MainClass {

	public static void main(String[] args) {
		CallableTask callableObj = new CallableTask();
		ExecutorService executor = Executors.newFixedThreadPool(5);
		Future<Integer> intResult = executor.submit(callableObj);

		try {
			if (!intResult.isDone()) {
				Thread.sleep(1000);
			}
			int result = intResult.get();
			System.out.println("result from future = " + result);
			executor.shutdown();
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
	}
}


import java.util.concurrent.Callable;

public class CallableTask implements Callable<Integer>{

	@Override
	public Integer call() throws Exception {
		int sum = 0;
		for (int i = 0; i < 10; i++) {
			sum+=i;
		}
		return sum;
	}
	
}


Executors also provides newCachedThreadPool method to create an executor with an expandable thread pool.
In the below example, we are creating an executor which operates upon an expandable thread pool.

package concurrency.threadpools;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class MainClass {

	public static void main(String[] args) {
		ExecutorService executor = Executors.newCachedThreadPool();
		Future<Integer> intResult = executor.submit(
					() -> {
						int sum = 0;
						for (int i = 0; i < 10; i++) {
							sum +=i;
						}
						return sum;
					}
				);

		try {
			if (!intResult.isDone()) {
				Thread.sleep(1000);
			}
			int result = intResult.get();
			System.out.println("result from future = " + result);
			executor.shutdown();
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
	}
	
}