Thread Executors: New Ways of Multi-Threading in Java

Running Single Thread in Java:

Dr. Vipin Kumar
9 min readJun 4, 2021

In this java, it was very simple to write multi-threading programming as shown in image below, just we have to extends Thread class or implements Runnable interface and then override run method in it.

Let’s take an example to remember or understand multi-threading programming in Java. In this program I created 2 classes, one is MyThread class, it is main class that have main methods to start execution of program and second class is ThreadTask, this class is multi-threading class, to make class multi-threading we need to extends Thread class or implements Runnable methods.

In main method, I created object of ThreadTask class and passed in the constructor of Thread class, after creating object, just call start method to start thread execution.

Analyze output also for clear understanding the execution of this program

public class MyThread

{

public static void main(String args[])

{

Thread thread1 = new Thread(new ThreadTask());

thread1.start();

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

class ThreadTask implements Runnable {

public void run()

{

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

Output:

Thread Name:main

Thread Name:Thread-0

Let’s understand internal visualization of thread also, using diagram below:

Here clearly visible that main thread is starting thread-0, thread-0 is doing its assigned task without any program, as usual threads do.

Running Multiple Thread in Java

As we run single thread above, it is very simple to run multiple thread also, two ways you can do this, first running same thread multiple times or running different threads each time. For just example purpose, I am running single thread multiple times, just by for lop, creating multiple objects of same thread class.

Let’s understand it by example given below:

public class MyMultiThread {

public static void main (String args[])

{

for(int i=0;i<10;i++)

{

Thread thread = new Thread (new ThreadTask());

thread.start();

}

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

class ThreadTask implements Runnable {

public void run()

{

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

Let’s understand internal visualization of thread also, using diagram below:

Here it is also visible that main thread is starting thread-0 to thread-9, all thread is doing their assigned task without any program, as usual as all threads do. But problems arise, when we create 1000 or more threads all together, due to this more memory and more CPU utilization also arise and create problems. Understand it in next topics.

Problems or Disadvantages in Older Multi-Threading Java Programming

If we create 1000 thread as shown in diagram below, it will create threads t1 to t99 by using for loop. But it is very expensive to create 1000 thread at a time, maybe we do not have enough memory or CPU resources for 1000 thread at a time. This type of approach can cause big problems in running program.

Let’s take a program to run 1000 thread at a time.

package Executors;

public class My1000Thread {

public static void main (String args[])

{

for(int i=0;i<1000;i++)

{

Thread thread = new Thread (new ThreadTask1000());

thread.start();

}

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

class ThreadTask1000 implements Runnable {

public void run()

{

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

Let’s understand internal visualization of thread also, using diagram below:

Here it is also visible that main thread is starting thread-0 to thread-999, all thread is doing their assigned task without any program, as usual as all threads do. But problems may arise, if we create 1000 or more threads all together in low end PC or Computer, due to this computer may crash or hang.

Solution of this kind of problems is ThreadPool, if we want to run 1000 or more thread on low end PC or computer, we can run it without any problem by using ThreadPool, ThreadPool is new modified approach to run thread in fixed pool with fixed number of size like 10, 20 or more. If we fixed pool size to 10 thread, then only 10 threads will run at a time in memory, and remaining thread have to wait in blocked queue, if any thread complete its execution then next thread start its execution, so only 10 thread at a time execute in memory, and one by one all threads get their chance to complete its task. This way we can protect or utilize computer resources better.

Thread Pool Executors

In Java, threads are mapped to system-level threads which are operating system’s resources. If you create threads uncontrollably, you may run out of these resources quickly. The context switching between threads is done by the operating system as well — in order to emulate parallelism. A simplistic view is that — the more threads you spawn; the less time each thread spends doing actual work. The Thread Pool pattern helps to save resources in a multithreaded application, and also to contain the parallelism in certain predefined limits.

When you use a thread pool, you write your concurrent code in the form of parallel tasks and submit them for execution to an instance of a thread pool. This instance controls several re-used threads for executing these tasks. The pattern allows you to control the number of threads the application is creating, their lifecycle, as well as to schedule tasks’ execution and keep incoming tasks in a queue.

Let’s understand thread pool using image below:

Thread Pool represents a group of worker threads that are waiting for the job and reuse many times. In case of thread pool, a group of fixed size threads are created. A thread from the thread pool is pulled out and assigned a job by the service provider. After completion of the job, thread is contained in the thread pool again. It provides Better Performance and Saves Time because there is no need to create new thread.

Java use java.util.concurrent package for implementing Thread Pool in java programs.

Let’s take an example to create 100 thread by using thread pool process:

import java.util.concurrent.*;

public class ThreadPoolEx {

public static void main(String[] args) {

// TODO Auto-generated method stub

ExecutorService service=Executors.newFixedThreadPool(10);

for(int i=0;i<100;i++)

{

service.execute(new PoolTask());

}

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

class PoolTask implements Runnable {

public void run()

{

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

Let’s understand internal visualization of thread also, using diagram below:

Here, it is visible that main thread is starting 100 threads and Executors is creating fixed thread pool of 10 threads, all thread is executing its tasks one by one in group or pool of 10 threads, if one thread complete its execution then next threads starts execution from blocking queue, like this way all threads completes its tasks one by one without over burdening computer resources.

How many thread can be execute in thread pool at once?

Thread pool is good solution for execute multiple thread without over resource computers, but big question rise in it also, how may thread to execute at once in thread pool, if we run large number of threads in thread pool like 1000 or more then resource will be over use, if we give less number of threads then resource will be underutilization. So what would be the best number of threads for thread pool. The answer is number of core in CPU, if we provide number of threads value in thread pool as per individual computer power or number of core in CPU, then without any problem thread will be run in all computers, weather computer is latest with high power or old with less power.

Let’s take an example to assign number of thread in thread pool with number of available core available in CPU.

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class ThreadWithCPU {

public static void main (String args[])

{

int coreCount=Runtime.getRuntime().availableProcessors(); //CPU Count

ExecutorService service =Executors.newFixedThreadPool(coreCount);

for(int i=0;i<1000;i++)

{

service.execute(new CPUTask());

}

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

class CPUTask implements Runnable {

public void run()

{

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

Types of Thread Pool Executors

1. Single Thread Executor

This thread pool executor has only one thread. It is used to execute tasks in a sequential manner. If the thread dies due to an exception while executing a task, a new thread is created to replace the old thread and the subsequent tasks are executed in the new one.

We create SingleThreadExecutor as given below:

ExecutorService executorService = Executors.newSingleThreadExecutor()

Let’s take an example to run 100 threads by using SingleThreadExecutor:

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class SingleThreadExecutors {

public static void main(String[] args) {

// TODO Auto-generated method stub

ExecutorService service=Executors.newSingleThreadExecutor();

for(int i=0;i<100;i++)

{

service.execute(new SingleTask());

}

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

class SingleTask implements Runnable {

public void run()

{

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

2. Fixed Thread Pool Executor

This thread pool has fixed N number of threads. The tasks submitted to the executor are executed by these N threads and if there is more task then that are stored on a LinkedBlockingQueue. This N number is usually the total number of the threads supported by the underlying processor.

We create FixedThreadPool as given below:

ExecutorService executorService = Executors.newFixedThreadPool(10);

Let’s take an example to create 100 thread by using FixedThreadPool Executors of 10 Pools:

import java.util.concurrent.*;

public class ThreadPoolEx {

public static void main(String[] args) {

// TODO Auto-generated method stub

ExecutorService service=Executors.newFixedThreadPool(10);

for(int i=0;i<100;i++)

{

service.execute(new PoolTask());

}

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

class PoolTask implements Runnable {

public void run()

{

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

3. Cached Thread Pool Executor

This Cached Thread Pool is mostly used where lots of short-lived parallel tasks to be executed. In fixed thread pool, number of thread is bound, but in cached thread pool number of threads is not bounded. If all the threads are busy executing some tasks and a new task comes, the pool will create and add a new thread to the executor. As soon as one of the threads becomes free, it will take up the execution of the new tasks. If a thread remains idle for 60 seconds, they are terminated and removed from cache.

Cached thread pool uses a SynchronousQueue to buffer the tasks if there are no active thread in the pool. Once a new task is submitted, a new thread is spawned and consumes the submitted task for processing. In a SynchronousQueue each insert operation must wait for a corresponding remove operation by another thread, and vice versa. A synchronous queue does not have any internal capacity, not even a capacity of one. This means as soon as a task is submitted, a thread needs to consume the task.

However, if cached thread pool is not managed correctly, or the tasks are not short-lived, the thread pool will be having lots of live threads, so this may lead to resource thrashing and hence performance drop.

We create CachedThreadPool as given below:

ExecutorService executorService = Executors.newCachedThreadPool();

Let’s take an example to understand ChacheThreaPool to create 1000 thread in it.

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class CachedThreadPool {

public static void main (String args[])

{

ExecutorService service =Executors.newCachedThreadPool();

for(int i=0;i<1000;i++)

{

service.execute(new Task());

}

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

static class Task implements Runnable {

public void run()

{

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

}

4. Scheduled Thread Pool Executor

This Scheduled Thread Pool Executor is used when we have a task that needs to be run at regular intervals or if we wish to delay a certain task.

We create ScheduledTheadPool as given below:

ScheduledExecutorService scheduledExecService = Executors.newScheduledThreadPool(10);

The tasks can be scheduled in ScheduledExecutor using either of the 3 methods schedule, scheduleAtFixedRate or scheduleWithFixedDelay.

The schedule() function executes the task after initialDelay and its executes task one time only

scheduledExecService.schedule(Runnable command, long initialDelay, TimeUnit unit)

The scheduleAtFixedRate() function executes first task after initialDelay time and then repeat the task with fixed interval of value given in period, irrespective of when the previous task ended.

scheduledExecService.scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

The scheduleWithFixedDelay() function executes first task after initialDelay time and then start the new threads with delay countdown of period value but only after the currently task completes.

scheduledExecService.scheduleWithFixedDelay(Runnable command, long initialDelay, long period, TimeUnit unit)

Let’s understand ScheduledThreadPool example by executing threads:

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;

public class ScheduledThreadPool {

public static void main (String args[])

{

ScheduledExecutorService service =Executors.newScheduledThreadPool(10);

service.schedule(new ScheduledTask(), 10, TimeUnit.SECONDS);

service.scheduleAtFixedRate(new ScheduledTask(),15,10,TimeUnit.SECONDS);

service.scheduleWithFixedDelay(new ScheduledTask(),15,10,TimeUnit.SECONDS);

}

static class ScheduledTask implements Runnable {

public void run()

{

System.out.println(“Thread Name:”+Thread.currentThread().getName());

}

}

}

--

--

Dr. Vipin Kumar

Assoc. Prof. , DCA & Assoc. Head (SD), SDFS, at KIET, PhD (CS) My YouTube Channel: Dr. Vipin Classes (https://www.youtube.com/channel/UC-77P2ONqHrW7h5r6MAqgSQ)