通过Executors.newVirtualThreadPerTaskExecutor()创建的虚拟线程,Thread.currentThread().getName()返回空字符串""。

5

我正在使用Java 19进行编程。我尝试使用新引入的虚拟线程,代码如下:

public static void main(String[] args)  {

    System.out.println("Started with virutal threads");
    try (ExecutorService virtualService = Executors.newVirtualThreadPerTaskExecutor()) {
        virtualService.submit(() -> System.out.println("[" + Thread.currentThread().getName() + "] virtual task 1"));
        virtualService.submit(() -> System.out.println("[" + Thread.currentThread().getName() + "] virtual task 2"));
    }
    System.out.println("Finished");
}

该程序的输出为:
Started with virutal threads
[] virtual task 2
[] virtual task 1
Finished

为什么Thread.currentThread().getName()没有任何名称?
跟进问题:如何识别彼此之间的虚拟线程?(如何识别它们)因此输出将如下所示
[thread-1] virtual task 2
[thread-0] virtual task 1

根据这篇文章所述,线程本地变量仍将作为当前正在执行的虚拟线程的实例本地变量。 - matt
@matt 很棒的文章,更加详细地阐述了这个主题。 - fascynacja
2个回答

4

简短概述

long threadId = Thread.currentThread().threadId() ;  // The thread ID is unique and remains unchanged during its lifetime.

线程名称可选

任何线程的名称都是完全可选的。

如果您愿意,可以命名一个线程。这在调试时非常方便。但您不应该期望有任何预设值。

特别是虚拟线程被指定为没有固定名称。引用Javadoc(我的强调):

默认情况下,虚拟线程没有线程名称。如果未设置线程名称,则getName方法返回空字符串。

线程ID

如果要标识Thread,请使用其ID,即long

  • 在Java 19+中,调用{{link1:Thread#threadId}}。
  • 在早期的Java中,调用{{link2:Thread#getId}}

引用Javadoc:

返回此线程的标识符。线程ID是在创建此线程时生成的正长整数。线程ID是唯一的,并在其生命周期内保持不变。


我不知道为什么我会在“名称”上卡住,以至于忘记了“ID”。 - fascynacja
@fascynacja 我也做过同样的事情! - Basil Bourque

3

我还不确定为什么线程名称为空,但我找到的临时解决方法可能是使用ThreadFactory,如下所示:

    final ThreadFactory factory = Thread.ofVirtual().name("named-thread-", 0).factory();
    try (var virtualService = Executors.newThreadPerTaskExecutor(factory)) {
        virtualService.submit(() -> System.out.println("[" + Thread.currentThread().getName() + "] virtual task 1"));
        virtualService.submit(() -> System.out.println("[" + Thread.currentThread().getName() + "] virtual task 2"));
    } 

在这种情况下,输出结果是:
[named-thread-0] virtual task 1
[named-thread-1] virtual task 2

1
我在javadoc中没有看到任何要求newVirtualThreadPerTaskExecutor创建的每个线程都必须具有唯一名称的内容。如果您需要唯一名称,则可能没有比这更好的解决方案了。线程名称从未被用于除调试之外的任何目的。JVM从未以任何方式依赖它们。 - Solomon Slow
5
Thread的javadoc中指出,虚拟线程默认没有名称。 - matt
@Solomon Slow 是的,我确实使用线程名称进行调试和日志记录。老实说,在某些情况下,没有线程名称的日志对我来说是无用的。问题在于,我认为我们都习惯了由执行器服务创建的平台线程默认分配名称的事实,那么为什么创建虚拟线程时会有所不同呢? - fascynacja
@matt 重申,“...没有默认名称。” 我希望的是,也许虚拟线程真的很容易创建,即使为每个线程分配一个新的名称字符串也会对开销产生明显的影响。 - Solomon Slow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接