x Java Java 8 JUnit JSON
  • XML
  • JDBC Spring Boot Microservices React Contact Us

    Java Executor and ExecutorService examples

    When you need more then one Thread to process multiple tasks in Java, you typically create multiple Threads and start them using new Thread(r).start(). But this way you need to manage Thread life cycle and you can't tune number of threads you actually need to perform the tasks. This is where java.util.Executor comes in very useful. You can use your choice of implementation of Executor interface and thus it lets you decouple the submission of task to execution of task.

    1) Examples of Executor interface implementation

    Executor that executes task asynchronously

    In below example we implement Executor which starts a new thread for each submitted task. A task is submitted by calling Executor execute(Runnable r) which accepts a Runnable type argument.

    import java.util.concurrent.Executor;
    
    public class TaskExecutor implements Executor {
        public void execute(Runnable r) {
            new Thread(r).start();
        }
    	
        public static void main(String[] args) {
            TaskExecutor taskExecutor = new TaskExecutor();
            Runnable runnable = () -> {System.out.println("Thread implementing Runnable started");};
                
            taskExecutor.execute(runnable);
        }
    }    

    Output :

    Thread implementing Runnable started		

    Executor that executes task synchronously

    Its not necessary that each submitted task would be run asynchronously. You can call Runnable run() inside the execute method to make the task run synchronously.

    import java.util.concurrent.Executor;
    
    public class TaskExecutor implements Executor {
        public void execute(Runnable r) {
            r.run();
        }
    	
        public static void main(String[] args) {
            TaskExecutor taskExecutor = new TaskExecutor();
            Runnable runnable = () -> {System.out.println("Thread implementing Runnable started");};
                
            taskExecutor.execute(runnable);
        }
    }    

    Output :

    Thread implementing Runnable started		

    2) ExecutorService and Executors examples

    There are various useful Executor implementations provide by Executors class is a factory of Executor which returns ExecutorService type that extends Executor.

    Below are some of the important Executor implementations:

    • newSingleThreadExecutor() returns an Executor with single thread. If there are more than one tasks submitted, only one task will be active and others will be put in a queue.
    • newFixedThreadPool() returns an Executor with fixed number of threads. If there are more tasks submitted than the thread pool size, then rest of the tasks will be put in a queue.
    • newCachedThreadPool() returns an Executor which creates new Thread as needed and put into a pool. Threads that are not used for sixty seconds are terminated and removed from the cache.
    • newSingleThreadScheduledExecutor() returns an Executor which will schedule the task to run after a certain interval.
    An Executor will accept a Runnable in submit(Runnable r) method which can be created as below using Lambda expression

    () -> System.out.println("Thread started")
    
    Below is the equivalent code:
    public class MyClass implements Runnable {
        public void run() {
            System.out.println("Thread started");
        }
    }    
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
        
    public class ExecutorServiceExample {
    	
        public static void main(String[] args) {
           
            // fixed thread pool with four threads
            ExecutorService service = Executors.newFixedThreadPool(4); 
            service.submit(() -> System.out.println("Thread started"));
            
            // cached thread pool
            service = Executors.newCachedThreadPool(); 
            service.submit(() -> System.out.println("Thread started"));
            
             // single thread pool
            service = Executors.newSingleThreadExecutor(); 
            service.submit(() -> System.out.println("Thread started"));
            service.shutdown();
            
            ScheduledExecutorService scheduledExecutorService
                = Executors.newSingleThreadScheduledExecutor();
            scheduledExecutorService.schedule(() -> System.out.println("Thread scheduled started"),
                2000, TimeUnit.MILLISECONDS);
                
            scheduledExecutorService.scheduleAtFixedRate(() 
                -> System.out.println("Thread scheduleAtFixedRate started"),
                1000, 2000, TimeUnit.MILLISECONDS);
    
        }
    }    

    Output :

    Thread started
    Thread started
    Thread started
    Thread scheduleAtFixedRate started
    Thread scheduled started
    Thread scheduleAtFixedRate started
    Thread scheduleAtFixedRate started    

    ExecutorService invokeAll() and invokeAny() example

    invokeAll() will take multiple Callable instances and start running all the tasks while invokeAny() will take multiple Callable instances and returns the result of the task which is completed successfully.

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
        
    public class ExecutorServiceExample {
    	
        public static void main(String[] args) {
           
            ExecutorService service = Executors.newFixedThreadPool(2); 
            List<Callable<String>> tasks = new ArrayList<>();
            tasks.add(() -> "task1");
            tasks.add(() -> "task2");
            service = Executors.newFixedThreadPool(2);
            try {
                service.invokeAll(tasks);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            tasks.forEach(task -> {
                try {
                    System.out.println(task.call());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            
            service.shutdown();
    
            service = Executors.newFixedThreadPool(2);
            try {
                System.out.println(service.invokeAny(tasks));
            } catch (InterruptedException | ExecutionException e1) {
                e1.printStackTrace();
            }
            
            service.shutdown();
        }
    
    }    

    Output :

    task1
    task2  

    3) Shutting down ExecutorService

    ExecutorService shutdown() example

    shutdown() will stop all the threads which are executed successfully and will not accept new tasks

    import java.util.concurrent.Executors;
    import java.util.concurrent.ExecutorService;
        
    public class MyThread implements Runnable {
        public void run() { 
            System.out.println(Thread.currentThread().getName()  + " started"); 
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()  + " complete"); 
        }
    	
        public static void main(String[] args) {
            MyThread myThread = new MyThread();
            
             // single thread pool
            ExecutorService service = Executors.newSingleThreadExecutor(); 
            service.submit(myThread);
            service.shutdown();
            
            service.submit(myThread);
        }
    }    

    Output :

    pool-1-thread-1 started
    Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@10dea4e 
    rejected from java.util.concurrent.ThreadPoolExecutor@647e05 [Shutting down, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]
        at java.util.concurrent.ThreadPoolExecutor$AbortPolicy .rejectedExecution(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor .reject(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor .execute(Unknown Source)
        at java.util.concurrent.AbstractExecutorService .submit(Unknown Source)
        at java.util.concurrent. Executors$DelegatedExecutorService.submit(Unknown Source)
        at MyThread.main(MyThread.java:24)
    pool-1-thread-1 complete 		

    ExecutorService shutdownNow() example

    shutdownNow() will stop all the running threads and will return list of the tasks that were awaiting execution In below example observe that first thread sleeps and is immediately shutdown and is not allowed to complete the task.

    import java.util.concurrent.Executors;
    import java.util.concurrent.ExecutorService;
        
    public class MyThread implements Runnable {
        public void run() { 
            System.out.println(Thread.currentThread().getName()  + " started"); 
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()  + " complete"); 
        }
    	
        public static void main(String[] args) {
            MyThread myThread = new MyThread();
            
             // single thread pool
            ExecutorService service = Executors.newSingleThreadExecutor(); 
            service.submit(myThread);
            service.shutdownNow();
        }
    }    

    Output :

    java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at MyThread.run(MyThread.java:8)
        at java.util.concurrent.Executors$RunnableAdapter.call (Unknown Source)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor .runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker .run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)
    pool-1-thread-1 started
    pool-1-thread-1 complete
    		

    References :