Java executor framework tutorial and best practices

Executors framework (java.util.concurrent.Executor), released with the JDK 5 in package java.util.concurrent is used to run the Runnable objects without creating new threads every time and mostly re-using the already created threads.

We all know about that there are two ways to create a thread in java. If you want to read more about their comparison, read this post. Creating a thread in java is a very expensive process which includes memory overhead also. So, it’s a good idea if we can re-use these threads once created, to run our future runnables.

In this post, I will write some demo programs demonstrating the usage of Executor and then we will talk about some best practices which you need to keep in mind while designing your next multi-threaded application.

If you want read more about other multi-threading topics, follow this link.

Basic usage demo application

In our demo application, we have two tasks running. Neither is expected to terminate, and both should run for the duration of the application’s life. I will try to write a main wrapper class such that:

If any task throws an exception, the application will catch it and restart the task.
If any task runs to completion, the application will notice and restart the task.

Below is the code sample of above required application:

package com.howtodoinjava.multiThreading.executors;

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

public class DemoExecutorUsage {

	private static ExecutorService executor = null;
	private static volatile Future taskOneResults = null;
	private static volatile Future taskTwoResults = null;

	public static void main(String[] args) {
		executor = Executors.newFixedThreadPool(2);
		while (true)
		{
			try
			{
				checkTasks();
				Thread.sleep(1000);
			} catch (Exception e) {
				System.err.println("Caught exception: " + e.getMessage());
			}
		}
	}

	private static void checkTasks() throws Exception {
		if (taskOneResults == null
				|| taskOneResults.isDone()
				|| taskOneResults.isCancelled())
		{
			taskOneResults = executor.submit(new TestOne());
		}

		if (taskTwoResults == null
				|| taskTwoResults.isDone()
				|| taskTwoResults.isCancelled())
		{
			taskTwoResults = executor.submit(new TestTwo());
		}
	}
}

class TestOne implements Runnable {
	public void run() {
		while (true)
		{
			System.out.println("Executing task one");
			try
			{
				Thread.sleep(1000);
			} catch (Throwable e) {
				e.printStackTrace();
			}
		}

	}
}

class TestTwo implements Runnable {
	public void run() {
		while (true)
		{
			System.out.println("Executing task two");
			try
			{
				Thread.sleep(1000);
			} catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}
}

Please do not forget to read best practices at the end of post.

Executing multiple tasks in a single thread

It’s not necessary that each Runnable should be executed in a separate thread. Sometimes, we need to do multiple jobs in a single thread and each job is instance of Runnable. To design this type of solution, a multi runnable should be used. This multi runnable is nothing but a collection of runnables which needs to be executed. Only addition is that this multi runnable is also a Runnable itself.

Below is the list of tasks which needs to be executed in a single thread.

package com.howtodoinjava.multiThreading.executors;

public class TaskOne implements Runnable {
	@Override
	public void run() {
		System.out.println("Executing Task One");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

public class TaskTwo implements Runnable {
	@Override
	public void run() {
		System.out.println("Executing Task Two");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

public class TaskThree implements Runnable {
	@Override
	public void run() {
		System.out.println("Executing Task Three");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

Lets create out multi runnable wrapper of above Tasks.

package com.howtodoinjava.demo.multiThread;

import java.util.List;

public class MultiRunnable implements Runnable {

    private final List<Runnable> runnables;

    public MultiRunnable(List<Runnable> runnables) {
        this.runnables = runnables;
    }

    @Override
    public void run() {
        for (Runnable runnable : runnables) {
        	 new Thread(runnable).start();
        }
    }
}

Now above multi runnable can be executed this way as in below program:

package com.howtodoinjava.demo.multiThread;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MultiTaskExecutor {

    public static void main(String[] args) {
        
        BlockingQueue<Runnable> worksQueue = new ArrayBlockingQueue<Runnable>(10);
        RejectedExecutionHandler rejectionHandler = new RejectedExecutionHandelerImpl();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 3, 10, TimeUnit.SECONDS, worksQueue, rejectionHandler);

        executor.prestartAllCoreThreads();
        
        List<Runnable> taskGroup = new ArrayList<Runnable>();
        taskGroup.add(new TestOne());
        taskGroup.add(new TestTwo());
        taskGroup.add(new TestThree());
 
        worksQueue.add(new MultiRunnable(taskGroup));
    }
}

class RejectedExecutionHandelerImpl implements RejectedExecutionHandler
{
    @Override
    public void rejectedExecution(Runnable runnable,
            ThreadPoolExecutor executor)
    {
        System.out.println(runnable.toString() + " : I've been rejected ! ");
    }
}

Best practices which must be followed

  1. Always run your java code against static analysis tools like PMD and FindBugs to look for deeper issues. They are very helpful in determining ugly situations which may arise in future.
  2. Always cross check and better plan a code review with senior guys to detect and possible deadlock or livelock in code during execution. Adding a health monitor in your application to check the status of running tasks is an excellent choice in most of the scenarios.
  3. In multi-threaded programs, make a habit of catching errors too, not just exceptions. Sometimes unexpected things happen and Java throws an error at you, apart from an exception.
  4. Use a back-off switch, so if something goes wrong and is non-recoverable, you don’t escalate the situation by eagerly starting another loop. Instead, you need to wait until the situation goes back to normal and then start again.
  5. Please note that the whole point of executors is to abstract away the specifics of execution, so ordering is not guaranteed unless explicitly stated.

Happy Learning !!

Lokesh has written 269 articles

I have 7 Years of rich experience in java technology. This has only increased my hunger to learn more. In this blog, i will be writing on different topics occasionally, and would love to engage in some meaningful serious discussions with you folks.

10 thoughts on “Java executor framework tutorial and best practices

  1. Manish says:

    Hey Lokesh,
    I have few doubts, please help me understand.
    (1) we have created one object of blockingQueue and used that in ThreadPoolExecutor, so what role it is playing in our current example.
    (2) What I think is we should not use MultiRunnable class and instead of below calls
    taskGroup.add(new TaskOne());
    taskGroup.add(new TaskTwo());
    taskGroup.add(new TaskThree());
    executor.execute(new MultiRunnable(taskGroup));
    we should use
    executor.execute(new TaskOne());
    executor.execute(new TaskTwo());
    executor.execute(new TaskThree());

    Because “runnable.run() in MultiRunnable” will execute the tasks within current parent thread instead of spawning new threads. Creating new threads in MultiRunnable will altogether means not utilizing the power of our Executor framework.

    Please let us know your expert thoughts.

    Regards,
    Manish Kr Agarwal
    manish.java@outlook.com

    1. Hey Manish, thanks for your comment here.

      I just looked again at code and realized it should been updated when I replied to mateen27. I don’t know how i missed here, because I usually make code changes immediately if I like the suggestion.

      I believe, both of your concerns should be resolved with latest code.

  2. mauro says:

    Please read at
    http://www.javaswingcomponents.com/blog/taming-swing-threads-part-3-swing-worker

    I would understand the use of swingworker .

    Into the link above it says :

    ————–
    Java 6 Release 18 and the SwingWorker.I have been working with the SwingWorker successfully since it was originally released in java 5. However there is a defect affecting the SwingWorker in Java 6 Release 18, which effectively brought a critical production system to its knees. The problem manifested in Java restricted the number of SwingWorkers that could be created. After launching a number of SwingWorkers, their thread pool reached capacity and no more workers could be created. The application became unresponsive as it needed SwingWorkers to fetch its required, however no new Workers could be created. Even though this problem was extremely serious, the workaround is very simplistic. Instead of calling the execute() method on the SwingWorker, simply pass the SwingWorker to your own Executor. executor.execute(swingWorker);

    ———————

    Whi?

    I have toi use always the Executor class for resolve the problem ?

    You can please explain me how instantitate the executor into that case?

    Tank you .
    Mauro

    1. I tried a few code changes and changing new Thread(runnable).start(); in place of runnable.run(); do the magic you want.

      public class MultiRunnable implements Runnable {

      private final List runnables;

      public MultiRunnable(List runnables) {
      this.runnables = runnables;
      }

      @Override
      public void run() {
      for (Runnable runnable : runnables) {
      new Thread(runnable).start();
      //runnable.run();
      }
      }
      }

  3. mateen27 says:

    Hi Lokesh,

    if i am not wrong…
    the multi executor is runnable and its executing other runnables

    the following is the output i am getting…. when i execute multi executor (second) program

    Executing task one
    Executing task one
    Executing task one …

    however i need this program bt its not working fine… means executing only thread one… not thread two or three…

    is thr any way to make this work…. ?

    Regards,
    Mateen SA

Want to ask any question? Or suggest anything?