Executor Service Example

package com.nkondrat.learning;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


public class ReusableThreadPoolExampleMain {

    private final ExecutorService executorService;

    public ReusableThreadPoolExampleMain(int threadPoolSize) {
        this.executorService = Executors.newFixedThreadPool(threadPoolSize);
    }

    public void executeTasksAndWaitForCompletion(final List<Callable<String>> tasks)
        throws InterruptedException {
        // Submit all tasks and wait for completion
        final List<Future<String>> futures = executorService.invokeAll(tasks);

        // Optionally, process the results or handle exceptions
        for (Future<String> future : futures) {
            try {
                final String result = future.get();// This will rethrow any exception caught during task execution
                System.out.println("Result in for loop: " + result);
            } catch (Exception e) {
                // Handle exception
                e.printStackTrace();
            }
        }
    }

    // Use this method to shut down the executor when it's no longer needed
    public void shutdown() {
        executorService.shutdown();
    }

    static class ExampleTask implements Callable<String> {
        private final int taskId;

        public ExampleTask(int taskId) {
            this.taskId = taskId;
        }

        @Override
        public String call() throws Exception {
            Thread.sleep(1000);
            // Task implementation
            System.out.println("Executing task-" + taskId);
            return String.format("Task-%d", taskId);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ReusableThreadPoolExampleMain threadPool =
            new ReusableThreadPoolExampleMain(3);

        List<Callable<String>> tasks = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            tasks.add(new ExampleTask(i));
        }

        threadPool.executeTasksAndWaitForCompletion(tasks);

        // The ExecutorService is still alive here and can be reused
        // Remember to shut down the executor when it's no longer needed
        // threadPool.shutdown();
    }
}