# Thread Pools and Executors

`ExecutorService` and `Executors` are used to manage and control thread execution efficiently. Thread pools reuse threads and reduce the overhead of thread creation.

**Using Executors to Create Thread Pools:**

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

class Task implements Runnable {
    private int taskId;

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

    public void run() {
        System.out.println("Task " + taskId + " is processing.");
    }
}

public class ThreadPoolExample {
    public static void main(String[] args) {
        int numberOfTasks = 5;
        ExecutorService executorService = Executors.newFixedThreadPool(numberOfTasks);

        for (int i = 1; i <= numberOfTasks; i++) {
            Task task = new Task(i);
            executorService.execute(task);
        }

        executorService.shutdown(); // Shutdown the executor service
    }
}
```

In the example, a fixed-size thread pool is created, and tasks are executed concurrently.
