Master Spring Boot 3 Virtual Threads: Prevent Daemon Issues & Keep Apps Alive
This guide explains how Spring Boot 3.2+ leverages JDK 21 virtual threads, demonstrates common pitfalls in non‑web applications—especially daemon thread termination—and shows how to enable keep‑alive configuration to ensure your tasks keep running, complete with code examples and performance insights.
Environment: SpringBoot 3.2.5 + JDK 21
1. Introduction
Since SpringBoot 3.2.0‑M1, virtual threads are supported. Virtual threads, introduced in JDK 21, run without binding to OS threads, offering much lower cost and memory usage than platform threads. Using them can improve overall system performance.
2. Practical Example (Non‑Web Application)
When the application does not include spring-boot-starter-web (or sets .web(WebApplicationType.NONE) ), it runs in non‑web mode.
<code>public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(SpringbootNonWebApplication.class)
.web(WebApplicationType.NONE)
.run(args);
}</code>In a non‑web app, the embedded server is not started. If no non‑daemon threads are running, the program exits automatically.
2.1 Start a Scheduled Task
Define a scheduled task that runs every 3 seconds.
<code>@Component
public class TaskComponent {
@Scheduled(fixedRate = 3000)
public void task1() throws Exception {
System.out.printf("Current thread: %s%n", Thread.currentThread());
// TODO: execute task
TimeUnit.SECONDS.sleep(1);
}
}</code>Enable the scheduler with @EnableScheduling .
2.2 Run Task with Virtual Threads
Enable virtual threads via Spring configuration:
<code>spring:
threads:
virtual:
enabled: true</code>After enabling, the task runs on a virtual thread, but the program terminates after a single log line because the virtual thread behaves like a daemon.
2.3 Daemon Thread Behavior
Simple thread example:
<code>Thread t = new Thread(() -> {
try {
System.out.println("start..." + System.currentTimeMillis());
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("over..." + System.currentTimeMillis());
});
t.start();</code>Output shows the thread finishes, then the JVM exits after non‑daemon threads complete.
Marking the thread as daemon makes the JVM exit immediately with no output.
Virtual threads are always daemon threads; Thread.setDaemon(true/false) has no effect on them.
2.4 Keep‑Alive Configuration for Virtual Threads
Starting with SpringBoot 3.2.0‑RC1, the spring.main.keep-alive property can keep the application alive when only daemon (virtual) threads are running.
<code>spring:
main:
keep-alive: true</code>With this setting, the application stays running instead of exiting.
2.5 Implementation Details
When spring.main.keep-alive=true , Spring Boot registers a listener that starts a non‑daemon thread which sleeps indefinitely, preventing the JVM from terminating.
<code>public class SpringApplication {
public ConfigurableApplicationContext run(String... args) {
// ...
prepareContext(...);
// ...
}
private void prepareContext(...) {
// ...
if (this.keepAlive) {
context.addApplicationListener(new KeepAlive());
}
// ...
}
}
private static final class KeepAlive implements ApplicationListener<ApplicationContextEvent> {
public void onApplicationEvent(ApplicationContextEvent event) {
if (event instanceof ContextRefreshedEvent) {
startKeepAliveThread();
} else if (event instanceof ContextClosedEvent) {
stopKeepAliveThread();
}
}
private void startKeepAliveThread() {
Thread thread = new Thread(() -> {
while (true) {
try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException ignored) {}
}
});
if (this.thread.compareAndSet(null, thread)) {
thread.setDaemon(false);
thread.setName("keep-alive");
thread.start();
}
}
private void stopKeepAliveThread() {
Thread thread = this.thread.getAndSet(null);
if (thread != null) {
thread.interrupt();
}
}
}</code>This simple mechanism ensures that virtual‑thread‑driven tasks can run without the application exiting prematurely.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.