Unsupported Method On Virtual Thread

ID

java.virtual_thread_unsupported_method

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Java

Tags

reliability

Description

Reports a call to setDaemon, setPriority or getThreadGroup on a local variable whose initializer creates a virtual thread — Thread.ofVirtual()…​.start(…​) / .unstarted(…​), or Thread.startVirtualThread(…​).

Virtual-ness is decided only from the local’s own initializer in the same method; a Thread parameter or field is never assumed virtual. setDaemon(true) is reported alongside setDaemon(false): it does not throw, but it is redundant, since a virtual thread’s daemon status can never be anything but true.

Rationale

Three Thread methods behave differently, and worse, on a virtual thread than on a platform one:

  • setDaemon(false) throws IllegalArgumentException — a virtual thread’s daemon status is always true and cannot be changed;

  • setPriority(int) silently does nothing — a virtual thread’s priority always stays Thread.NORM_PRIORITY;

  • getThreadGroup() returns a dummy, empty placeholder group that should not be used for anything.

Thread worker = Thread.ofVirtual().unstarted(() -> process());
worker.setPriority(Thread.MAX_PRIORITY); // silently has no effect
worker.setDaemon(false);                 // throws IllegalArgumentException
worker.setDaemon(true);                  // redundant: a virtual thread is always a daemon
ThreadGroup group = worker.getThreadGroup(); // a dummy, empty placeholder group
worker.start();

Remediation

Drop the call entirely for a virtual thread — none of these three properties can be configured on one:

Thread worker = Thread.ofVirtual().unstarted(() -> process());
worker.start();

© 2026 Xygeni. All rights reserved