Contents

Naming virtual threads

Writen by: David Vlijmincx

Introduction

This post looks into naming virtual threads in three different ways. We will first use the virtual thread builder method. After that, we look into creating a thread factory and how to use it together with an ExecutorService.

Naming a virtual thread

In the following example, I set the name of the virtual thread using the builder method. When you create a thread using the static builder method ofVirtual() you can set the name using the .name() method.

1
2
3
Thread virtualThread = Thread.ofVirtual()
        .name("my-name")
        .start(() -> System.out.println(Thread.currentThread()));

When you run the previous thread the result in the console looks something like the following example. Notice that we can see me-name at the beginning. This is the name I gave the thread.

1
VirtualThread[#32,my-name]/runnable@ForkJoinPool-1-worker-1

Naming Virtual threads using a factory

Naming a lot of virtual threads is easier with a factory. Using the same builder method ofVirtual() we can create a thread factory. You can do this by calling the .factory() method after setting the name.

In the following example, we create a factory and use it to create new virtual threads.

1
2
3
ThreadFactory factory = Thread.ofVirtual().name("my-name").factory();
Thread vt = factory.newThread(() -> System.out.println(Thread.currentThread()));
vt.start();

When you run the previous thread the result in the console looks something like the following example. Notice that we can see me-name at the beginning. This is the name I gave the thread.

1
VirtualThread[#32,my-name]/runnable@ForkJoinPool-1-worker-1

Naming Virtual threads using an ExecutorService

To name virtual threads created by an ExecutorService you need to create your factory first. You can't name virtual threads using the newVirtualThreadPerTaskExecutor. If you want to do so you need to use the newThreadPerTaskExecutor and a virtual thread factory. The end-result behaves the same, a virtual thread will be created for each task, but you will have full control over the factory.

In the following example, I create a virtual thread factory that names my virtual threads my-name followed by a number. Next, I pass this factory to the newThreadPerTaskExecutor. When I create virtual threads using the newThreadPerTaskExecutor they will get the name my-name followed by their number.

1
2
3
4
5
6
ThreadFactory factory = Thread.ofVirtual().name("my-name", 0L).factory();

try (ExecutorService e = Executors.newThreadPerTaskExecutor(factory);) {
    e.submit(() -> System.out.println(Thread.currentThread()));
    e.submit(() -> System.out.println(Thread.currentThread()));
}

In the console, you can see their name appear followed by their number.

1
2
VirtualThread[#34,my-name1]/runnable@ForkJoinPool-1-worker-2
VirtualThread[#32,my-name0]/runnable@ForkJoinPool-1-worker-1

Conclusion

You can name virtual threads using the static builder method .ofVirtual(). The same builder method can be used to create a factory to create new threads with or as input for an ExecutorService.

Further reading

More about virtual threads in Java: