Java Executor Framework

Loading

The Java Executor Framework is a powerful and flexible framework for managing and executing threads in Java. It simplifies thread management by abstracting the low-level details of thread creation, scheduling, and execution. The framework is part of the java.util.concurrent package and provides several interfaces and classes for thread pooling and task execution.


1. Key Components of the Executor Framework

The Executor Framework consists of the following key components:

  1. Executor: The root interface for executing tasks.
  2. ExecutorService: A sub-interface of Executor that provides methods for managing the lifecycle of threads and tasks.
  3. ScheduledExecutorService: A sub-interface of ExecutorService that supports scheduling tasks for future or periodic execution.
  4. ThreadPoolExecutor: A concrete implementation of ExecutorService that manages a pool of threads.
  5. Executors: A utility class for creating thread pools and executor services.

2. Creating Thread Pools

The Executors class provides factory methods for creating different types of thread pools:

a. Fixed Thread Pool

  • Creates a thread pool with a fixed number of threads.
  • Tasks are executed concurrently by the available threads.

Example: Fixed Thread Pool

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

public class FixedThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);

        Runnable task1 = () -> System.out.println("Task 1 executed by " + Thread.currentThread().getName());
        Runnable task2 = () -> System.out.println("Task 2 executed by " + Thread.currentThread().getName());
        Runnable task3 = () -> System.out.println("Task 3 executed by " + Thread.currentThread().getName());

        executor.submit(task1);
        executor.submit(task2);
        executor.submit(task3);

        executor.shutdown(); // Shutdown the executor
    }
}

b. Cached Thread Pool

  • Creates a thread pool that creates new threads as needed but reuses previously constructed threads when they are available.
  • Suitable for short-lived asynchronous tasks.

Example: Cached Thread Pool

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

public class CachedThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();

        Runnable task1 = () -> System.out.println("Task 1 executed by " + Thread.currentThread().getName());
        Runnable task2 = () -> System.out.println("Task 2 executed by " + Thread.currentThread().getName());
        Runnable task3 = () -> System.out.println("Task 3 executed by " + Thread.currentThread().getName());

        executor.submit(task1);
        executor.submit(task2);
        executor.submit(task3);

        executor.shutdown(); // Shutdown the executor
    }
}

c. Single Thread Executor

  • Creates a thread pool with a single thread.
  • Tasks are executed sequentially.

Example: Single Thread Executor

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

public class SingleThreadExecutorExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();

        Runnable task1 = () -> System.out.println("Task 1 executed by " + Thread.currentThread().getName());
        Runnable task2 = () -> System.out.println("Task 2 executed by " + Thread.currentThread().getName());
        Runnable task3 = () -> System.out.println("Task 3 executed by " + Thread.currentThread().getName());

        executor.submit(task1);
        executor.submit(task2);
        executor.submit(task3);

        executor.shutdown(); // Shutdown the executor
    }
}

d. Scheduled Thread Pool

  • Creates a thread pool that can schedule tasks to run after a delay or periodically.

Example: Scheduled Thread Pool

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolExample {
    public static void main(String[] args) {
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

        Runnable task = () -> System.out.println("Task executed by " + Thread.currentThread().getName());

        // Schedule task to run after 2 seconds
        executor.schedule(task, 2, TimeUnit.SECONDS);

        // Schedule task to run every 3 seconds after an initial delay of 1 second
        executor.scheduleAtFixedRate(task, 1, 3, TimeUnit.SECONDS);

        // Shutdown the executor after 10 seconds
        executor.schedule(() -> executor.shutdown(), 10, TimeUnit.SECONDS);
    }
}

3. Submitting Tasks

The ExecutorService provides methods for submitting tasks for execution:

  • submit(Runnable task): Submits a task for execution and returns a Future object.
  • execute(Runnable task): Executes the task without returning a result.
  • invokeAll(Collection<Callable<T>> tasks): Executes all tasks and returns a list of Future objects.
  • invokeAny(Collection<Callable<T>> tasks): Executes all tasks and returns the result of the first completed task.

Example: Submitting Tasks

import java.util.concurrent.*;

public class SubmitTasksExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // Submit a Runnable task
        Future<?> future1 = executor.submit(() -> System.out.println("Runnable Task"));

        // Submit a Callable task
        Future<String> future2 = executor.submit(() -> "Callable Task");

        // Get the result of the Callable task
        System.out.println("Callable Task Result: " + future2.get());

        executor.shutdown(); // Shutdown the executor
    }
}

4. Shutting Down Executors

  • shutdown(): Initiates an orderly shutdown of the executor. Previously submitted tasks are executed, but no new tasks are accepted.
  • shutdownNow(): Attempts to stop all actively executing tasks and halts the processing of waiting tasks.

Example: Shutting Down Executors

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

public class ShutdownExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);

        Runnable task = () -> System.out.println("Task executed by " + Thread.currentThread().getName());

        executor.submit(task);
        executor.submit(task);

        executor.shutdown(); // Shutdown the executor

        // Attempting to submit a new task after shutdown will throw RejectedExecutionException
        try {
            executor.submit(task);
        } catch (Exception e) {
            System.out.println("Task rejected: " + e.getMessage());
        }
    }
}

5. Handling Task Results with Future

The Future interface represents the result of an asynchronous computation. It provides methods to check if the computation is complete, retrieve the result, or cancel the task.

Example: Using Future

import java.util.concurrent.*;

public class FutureExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(2);

        Callable<String> task = () -> {
            Thread.sleep(2000); // Simulate a long-running task
            return "Task Result";
        };

        Future<String> future = executor.submit(task);

        System.out.println("Task submitted");

        // Wait for the result
        String result = future.get();
        System.out.println("Task Result: " + result);

        executor.shutdown(); // Shutdown the executor
    }
}

6. Best Practices

  • Use thread pools to manage resources efficiently.
  • Prefer Callable over Runnable if you need to return a result.
  • Always shutdown the executor to release resources.
  • Use Future to handle task results and exceptions.

By mastering the Java Executor Framework, you can efficiently manage and execute tasks in a multi-threaded environment!

Leave a Reply

Your email address will not be published. Required fields are marked *