Docs

Documentation versions (currently viewingVaadin 25.4 (pre-release))

Vaadin Executor

Configuring and using Vaadin Executor to run background tasks.

The Vaadin Executor provides a centralized mechanism for managing asynchronous tasks in Vaadin applications. It offers a configurable thread pool that can be used for executing background operations without blocking the UI thread.

This feature is particularly useful for performing time-consuming operations asynchronously, executing background tasks that should not block the UI, managing concurrent operations efficiently and integrating with framework-specific task execution mechanisms, like Spring TaskExecutor or CDI ManagedExecutor.

By default, Vaadin creates a thread pool executor with the following configuration:

  • Core pool size: 8 threads

  • Maximum pool size: Unbounded (Integer.MAX_VALUE)

  • Keep-alive time: 60 seconds for idle threads

  • Custom thread factory that creates daemon threads

  • Core threads are allowed to time out when idle

This default configuration is suitable for most applications but can be customized as needed.

Accessing and Using the Executor

You can access the executor through the VaadinService instance:

Source code
Java
Executor executor = VaadinService.getCurrent().getExecutor();

// Execute a task asynchronously
executor.execute(() -> {
    // Your background task here
    myService.longRunningTask();
});

// Execute a task asynchronously using CompletableFuture
CompletableFuture.supplyAsync(myService::longRunningTask, executor)
    .thenAccept(this::handleResult);

Code that runs in the executor doesn’t hold the session lock. To update the user interface from it, use signals or the UI.access() method, as described in Pushing UI Updates. For guidance on running background jobs and starting tasks from the user interface, see Background Jobs and User Interface Threads.

Configuring a Custom Executor

In standard Java applications, you can customize the executor by registering a VaadinServiceInitListener and providing your own executor implementation:

Source code
CustomExecutorServiceInitListener.java
package com.example;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.vaadin.flow.server.ServiceInitEvent;
import com.vaadin.flow.server.VaadinServiceInitListener;

public class CustomExecutorServiceInitListener implements VaadinServiceInitListener {
    @Override
    public void serviceInit(ServiceInitEvent event) {
        ThreadPoolExecutor customExecutor = new ThreadPoolExecutor(
            16, // Core pool size
            32, // Maximum pool size
            120, // Keep-alive time
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(),
            r -> {
                Thread thread = new Thread(r, "CustomVaadinExecutor-" + r.hashCode());
                thread.setDaemon(true);
                return thread;
            });

        // Allow core threads to time out
        customExecutor.allowCoreThreadTimeOut(true);

        // Set the custom executor
        event.setExecutor(customExecutor);
    }
}

Register your listener using Java’s ServiceLoader mechanism by creating a file at META-INF/services/com.vaadin.flow.server.VaadinServiceInitListener. The file should contain the fully qualified name of your implementation class: com.example.CustomExecutorServiceInitListener

When configuring a custom Thread Pool, consider the following best practices:

  • Core Pool Size: Set based on the number of concurrent tasks your application typically handles. A good starting point is the number of CPU cores.

  • Maximum Pool Size: Set to a reasonable upper limit to prevent resource exhaustion. Consider your server’s memory and CPU constraints.

  • Queue Capacity: Use a bounded queue to prevent memory issues when task submission rate exceeds execution rate.

  • Use descriptive thread names to make debugging easier.

  • Make threads daemon threads (Thread.setDaemon(true)) to prevent them from blocking JVM shutdown.

  • Allow core threads to time out if your application has periods of inactivity

For framework integrations, consult the specific documentation pages for Spring, CDI and Quarkus.

2EF7B593-E426-479E-89D7-E62667D316C2