Week 50 — What is an `Executor` (from `java.util.concurrent`) and how can it be used?

Question of the Week #50
What is an Executor (from java.util.concurrent) and how can it be used?
8 Replies
Eric McIntyre
Eric McIntyre12mo ago
Executor allows to submit tasks that are processed asynchronously. There are different executors that run the tasks in thread pools. For example, Executors.newSingleThreadExecutor() executes all submitted tasks in a single thread while Executors.newCachedThreadPool() creates as many threads as needed. For example, the following code submits to tasks to a single-threaded Executor. It would first print println after submitting tasks, wait one second, print Task 1, wait another second and then print Task 2. Since both tasks are executed in the same thread, the second task needs to wait for the first task to finish.
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(()->{
try{
Thread.sleep(1000);
System.out.println("Task 1");
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
});
executor.execute(()->{
try{
Thread.sleep(1000);
System.out.println("Task 2");
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
});
System.out.println("println after submitting tasks");
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(()->{
try{
Thread.sleep(1000);
System.out.println("Task 1");
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
});
executor.execute(()->{
try{
Thread.sleep(1000);
System.out.println("Task 2");
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
});
System.out.println("println after submitting tasks");
Eric McIntyre
Eric McIntyre12mo ago
Since virtual threads were introduced, a new executor, Executors.newVirtualThreadPerTaskExecutor() has been added. This executor creates a virtual thread for every submitted task. If we use the above code with that executor, it would not wait one second between printing Task 1 and Task 2:
Executor executor = Executors.newVirtualThreadPerTaskExecutor();
executor.execute(()->{
try{
Thread.sleep(1000);
System.out.println("Task 1");
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
});
executor.execute(()->{
try{
Thread.sleep(1000);
System.out.println("Task 2");
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
});
System.out.println("println after submitting tasks");
Executor executor = Executors.newVirtualThreadPerTaskExecutor();
executor.execute(()->{
try{
Thread.sleep(1000);
System.out.println("Task 1");
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
});
executor.execute(()->{
try{
Thread.sleep(1000);
System.out.println("Task 2");
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
});
System.out.println("println after submitting tasks");
📖 Sample answer from dan1st
Eric McIntyre
Eric McIntyre12mo ago
An object that allows you to execute runnable tasks. Does not need to be asynchronous task either and provides away to decouple the tasks submissions.
Submission from smokeintitan
Eric McIntyre
Eric McIntyre12mo ago
The executor runs runnables! We use it to keep the tricky work of “how to run” separate from “submitting something to run”. It lets us construct tasks as runnables, which we can then “merely” submit to the executor.
Submission from fm10esk
Eric McIntyre
Eric McIntyre12mo ago
Executor is an interface in the package java.util.concurrent for higher level replacement for managing threads, other than directly manipulating Thread objects. CODE EXAMPLE:
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class Example {
public static void main(String[] args) {
Executor executor = Executors.newFixedThreadPool(2);
executor.execute(new MyTask("Task 1"));
executor.execute(new MyTask("Task 2"));
executor.execute(new MyTask("Task 3"));
}
}

class MyTask implements Runnable {
private String taskName;

public MyTask(String taskName) {
this.taskName = taskName;
}

@Override
public void run() {
System.out.println("Executing task: " + taskName + " on thread " + Thread.currentThread().getName());
}
}
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class Example {
public static void main(String[] args) {
Executor executor = Executors.newFixedThreadPool(2);
executor.execute(new MyTask("Task 1"));
executor.execute(new MyTask("Task 2"));
executor.execute(new MyTask("Task 3"));
}
}

class MyTask implements Runnable {
private String taskName;

public MyTask(String taskName) {
this.taskName = taskName;
}

@Override
public void run() {
System.out.println("Executing task: " + taskName + " on thread " + Thread.currentThread().getName());
}
}
Submission from cvs0.
Eric McIntyre
Eric McIntyre12mo ago
Deals with initiation and also deals with controlling the execution of threads.
Submission from PNJ3.0#1519
Eric McIntyre
Eric McIntyre12mo ago
The Executor from java.util.concurrent package, is a interface which provides better replacement for managing and executing threads compared to Threads in Java. Another cool thing about it is, since it's a interface a it abstracts the details of thread creation, pooling, and lifecycle management which then again results in a more efficient development for big/concurrent applications The actual purpose of the Executor is to decouple task submission from the specifics of how each task will be run and lastly it then helps the developers to maintain the logic of their concurrent applications more than just focusing on minor details of the threads How would one use Executor, Lets get started with a Runnable task
class ExampleTask implements Runnable {
public void run() {
int num = 0;
System.out.println("Counting intervals");
num = num + 1;
}
}

// This was a example on how to define a task, a Runnable task we can also define a callable task
class ExampleTask implements Runnable {
public void run() {
int num = 0;
System.out.println("Counting intervals");
num = num + 1;
}
}

// This was a example on how to define a task, a Runnable task we can also define a callable task
Creating a executor service
ExecutorService service = Executors.newFixedThreadPool(5);
// In this example Executors has a #newFixedThreadPool static method what it does is takes in the number of threads, which then is used to execute tasks
ExecutorService service = Executors.newFixedThreadPool(5);
// In this example Executors has a #newFixedThreadPool static method what it does is takes in the number of threads, which then is used to execute tasks
Submitting Tasks
service.submit(new ExampleTask());

// this would then submit the task to the executor and not only that this method also returns a object Future which can be used to monitor progress or retrieve of result
service.submit(new ExampleTask());

// this would then submit the task to the executor and not only that this method also returns a object Future which can be used to monitor progress or retrieve of result
Lastly how to shutdown a executor
service.shutdown();

// This shutdowns the executor and prevents new tasks from happening
service.shutdown();

// This shutdowns the executor and prevents new tasks from happening
Submission from xenofic
Eric McIntyre
Eric McIntyre12mo ago
⭐ Submission from pablohdz
Want results from more Discord servers?
Add your server