HowToDoInJava

  • Python
  • Java
  • Spring Boot
  • Dark Mode
Home / Java / Multi-threading / Java executor framework tutorial and best practices

Java executor framework tutorial and best practices

Java executor framework (java.util.concurrent.Executor), released with the JDK 5 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 how to create threads in Java.

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 executor framework tutorial, 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.

1. Java executor framework example

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.

2. Java executor framework – multi runnable

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 ! ");
    }
}

3. Java executor framework best practices

  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 !!

Was this post helpful?

Let us know if you liked the post. That’s the only way we can improve.
TwitterFacebookLinkedInRedditPocket

About Lokesh Gupta

A family guy with fun loving nature. Love computers, programming and solving everyday problems. Find me on Facebook and Twitter.

Feedback, Discussion and Comments

  1. Yovel

    April 7, 2020

    Hey, I know it is not that important, however why example 2 (multi runnable) has three public classes in a file. It’s probably a little mistake. Anyway, you’re doing a great job creating this keep going!

  2. Thomas Lee S

    January 10, 2020

    Hi Lokesh

    Thank you for the great post.

  3. Tasawar

    October 17, 2016

    Hi Lokesh!
    Thanks for a fine tutorial.
    I would like you to update the post as said by mateen27 and Manish. This will improve the post.

  4. Gaurav Dalal

    March 25, 2016

    Hi,
    Great ARTICLE. Nice learning.
    I actually used Executor framework in my code but its now working as expected. I have a List object, in the FOR LOOP , I am preparing a object of a class and adding the same to EXECUTOR.EXECUTE(). Approach that I am trying is Given below. Challenge I am facing is Objects of Pooling class will be created depending on the size of list. Say I have a list of size 3. So 3 Objects of Polling should get added to (“Executor es”) es.execute(polling), but only 2 objects of Pooling are getting processed by execute method. Its bit weird And I don’t know how to fix this. PLEASE HELP!. THANKS IN ADVANCE.

     
    Class A{
    
    //some variables
    void method(){
    ExecutorService es;
    es = Executors.newFixedThreadPool(10);	
    for(int i = 0; i <list.size();){
    Pooling polling = new Pooling();
    i++;
    es.execute(pooling);		
    }
    es.shutdown();
    }
    
    private DataFileElm dataFileElm;
    	class Pooling implements Runnable {
    
    		public Pooling(DataFileElm dataFileElm, File workDir,Connection con,List<DataManifestElm> dataPrimayList,long processId, long subprocessId) {
    			super();
    					
    			
    		}
    
    			@Override
    			public void run() {
    				System.out.println(Thread.currentThread().getName()+ "--- Started Asynchronous task ");
    				UCRCheckin checkin = new UCRCheckin();
    				UCRMetadata metadata = new UCRMetadata();
    				try {						
    				//Some Bussiness logic
    					
    					System.out.println("run :: Polling :: Inside run method "+dataFileElm.getDataFile().getName());
    					metadata.setFile(dataFileElm.getDataFile());		
    					
    				
    					final long start = System.currentTimeMillis();
    								
    							checkin.checkinFile(metadata,dataFileElm.getLogError(),CheckinThread.processId,CheckinThread.subProcessJobId,CheckinThread.con);					
    							long end = System.currentTimeMillis();
    							System.out.println("Time taken in ms " + (end - start));
    
    								}catch (Exception e) {
    											
    									}finally{
    								try {
    									dataFileElm.getLogError().logErrorMessages(conn);			
    									
    								} catch (SQLException e1) {
    									
    									log.error("File Processing Exception in CheckinThread.java"+e1);
    							}
    					}
    				
    			}
    	}
    
    • Gaurav Dalal

      March 25, 2016

      CORRECTION:: I actually used Executor framework in my code but its “NOT”working as expected.

  5. Keshav

    December 15, 2015

    Hi Lokesh,
    Thanks for the informative tutorial,
    do we need a while loop for those threads (TestOne and TestTwo)?

    class TestOne implements Runnable {
        public void run() {
            while (true)
            {
    

    Since we are resubmitting the thread again using the executor framework, that while loop is redundant.

    • Lokesh Gupta

      December 15, 2015

      It’s optional. I wanted to make it run indefinitely.

  6. Gaurav

    September 25, 2014

    Hi,

    In your example DemoExecutorUsage, why you have created Future class objects, where no class implements Callable interface?

    • Lokesh Gupta

      September 25, 2014

      Hi Gaurav, Thanks for asking this very good question. In my understanding, Callable is different from Runnable in only one sense i.e. it can return some value. Otherwise they may be used alternatively in any similar situation without breaking the system. Please refer to ExecutorService.submit(Runnable) method. I am using same method it just for checking the status of running tasks, without expecting any rerun value from them.

      I modified first example a bit and now observe the outputs.

      public class DemoTaskExecutorVersion2 {
       
          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(&amp;quot;Caught exception: &amp;quot; + e.getMessage());
                  }
              }
          }
       
          private static void checkTasks() throws Exception {
              if (taskOneResults == null
                      || taskOneResults.isDone()
                      || taskOneResults.isCancelled())
              {
                  System.out.println(&amp;quot;Starting task one.......&amp;quot;);
                  taskOneResults = executor.submit(new TestOne());
              }
       
              if (taskTwoResults == null
                      || taskTwoResults.isDone()
                      || taskTwoResults.isCancelled())
              {
                 System.out.println(&amp;quot;Starting task two.......&amp;quot;);
                  taskTwoResults = executor.submit(new TestTwo());
              }
          }
      }
       
      class TestOne implements Runnable {
          @Override
         public void run() {
              {
                  System.out.println(&amp;quot;Executing task one&amp;quot;);
                  try
                  {
                      Thread.sleep(5000);
                  } catch (Throwable e) {
                      e.printStackTrace();
                  }
                  System.out.println(&amp;quot;Task one completed&amp;quot;);
              }
       
          }
      }
       
      class TestTwo implements Runnable {
          @Override
         public void run() {
              {
                  System.out.println(&amp;quot;Executing task two&amp;quot;);
                  try
                  {
                      Thread.sleep(8000);
                  } catch (Throwable e) {
                      e.printStackTrace();
                  }
                  System.out.println(&amp;quot;Task two completed&amp;quot;);
              }
          }
      }
      
      Output:
      
      Starting task one.......
      Starting task two.......
      Executing task one
      Executing task two
      
      Task one completed
      Starting task one.......
      
      Executing task one
      
      Task two completed
      Starting task two.......
      
      Executing task two
      
      Task one completed
      Starting task one.......
      
      Executing task one
      

      As soon as any task is completed, application is able to identify it and restart it; that’s whole purpose of this exercise. Monitor threads should never stop, and if they are stopped somehow, then application should start them again.

      I hope that I am making sense.

  7. Hitmannura Salk

    July 24, 2014

    i did it but not working, so i post the question here, i code in eclipse-kepler for core java

  8. Hitmannura Salk

    July 24, 2014

    got output :
    Executing Task Two
    Executing Task One
    Executing Task Three
    was successful ,
    but not exiting programme after Executing all the Threads needed.

    • Lokesh Gupta

      July 24, 2014

      Use System.exit(0).

  9. Ram Krishna Dixit

    June 26, 2014

    Hi Lokesh,
    Very Informative topic however when I am executing given example code (Class DemoExecutorUsage ) it continuously run and throws NullPointerException . There should be not null checks.

    • Lokesh Gupta

      June 26, 2014

      Yes it continuously runs.. but NullPointerException should not happen. Where it occur? Can you please share some exception trace.

  10. Rampal

    June 17, 2014

    Hi Lokesh,
    What would be the difference between these two code snippets :
    worksQueue.add(new MultiRunnable(taskGroup));
    and
    executor.execute(new MultiRunnable(taskGroup));

    Both of these would give the similar end results

    • Lokesh Gupta

      June 17, 2014

      Yes, they would give the similar end results.

  11. shoumesh

    February 9, 2014

    Lokesh Please Explain the Executor framework part of this program

    • Lokesh Gupta

      February 9, 2014

      I will come up in a different post soon.

  12. Manish

    October 14, 2013

    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

    • Lokesh Gupta

      October 14, 2013

      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.

  13. mauro

    September 16, 2013

    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

  14. mateen27

    March 16, 2013

    here is the link

    https://docs.google.com/file/d/0B0_wI0TkntqKeTMxeWgtWHFnakE/edit?pli=1
    it has src dir only with all java files…

    Please let me know if its working (because i have written an swing application application using threads which is crashing so i want to use this concept… as runnable will resrart even if it crashes)

    Regards.
    Mateen SA.

    • Lokesh Gupta

      March 17, 2013

      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();
      }
      }
      }

  15. mateen27

    March 14, 2013

    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

    • Lokesh Gupta

      March 14, 2013

      Hi, Yes multi runnable is group of runnables.

      Can you please post the complete code of all your classes so that i can better be able to help you out??

Comments are closed on this article!

Search Tutorials

Java Concurrency Tutorial

  • Java Concurrency – Introduction
  • Concurrency Evolution
  • Thread Safety
  • Concurrency vs. Parallelism
  • Compare and Swap [CAS]
  • synchronized keyword
  • Object vs. Class Level Locking
  • Runnable vs. Thread
  • wait(), notify() and notifyAll()
  • Yield() vs. Join()
  • Sleep() vs. Wait()
  • Lock vs. Monitor
  • Callable + Future
  • UncaughtExceptionHandler
  • Throttling Task Submission
  • Executor Best Practices
  • Inter-thread Communication
  • Write and Resolve Deadlock

Java Concurrency Utilities

  • AtomicInteger
  • Lock
  • ThreadFactory
  • ThreadLocal
  • ExecutorService
  • ThreadPoolExecutor
  • FixedSizeThreadPoolExecutor
  • ScheduledThreadPoolExecutor
  • Semaphore
  • Binary Semaphore
  • BlockingQueue
  • DelayQueue
  • ConcurrentLinkedDeque
  • CountDownLatch
  • ForkJoinPool

Java Tutorial

  • Java Introduction
  • Java Keywords
  • Java Flow Control
  • Java OOP
  • Java Inner Class
  • Java String
  • Java Enum
  • Java Collections
  • Java ArrayList
  • Java HashMap
  • Java Array
  • Java Sort
  • Java Clone
  • Java Date Time
  • Java Concurrency
  • Java Generics
  • Java Serialization
  • Java Input Output
  • Java New I/O
  • Java Exceptions
  • Java Annotations
  • Java Reflection
  • Java Garbage collection
  • Java JDBC
  • Java Security
  • Java Regex
  • Java Servlets
  • Java XML
  • Java Puzzles
  • Java Examples
  • Java Libraries
  • Java Resources
  • Java 14
  • Java 12
  • Java 11
  • Java 10
  • Java 9
  • Java 8
  • Java 7

Meta Links

  • About Me
  • Contact Us
  • Privacy policy
  • Advertise
  • Guest and Sponsored Posts

Recommended Reading

  • 10 Life Lessons
  • Secure Hash Algorithms
  • How Web Servers work?
  • How Java I/O Works Internally?
  • Best Way to Learn Java
  • Java Best Practices Guide
  • Microservices Tutorial
  • REST API Tutorial
  • How to Start New Blog

Copyright © 2020 · HowToDoInjava.com · All Rights Reserved. | Sitemap

  • Sealed Classes and Interfaces