这里的每个人似乎都认为实现 Runnable 是要走的路,我并不真的不同意他们,但我认为也有扩展 Thread 的情况,事实上你已经在你的代码中展示了它。
如果你实现了 Runnable 那么实现 Runnable 的类无法控制线程名,它是可以设置线程名的调用代码,如下所示:
new Thread(myRunnable,"WhateverNameiFeelLike");
但是,如果您扩展 Thread,那么您可以在类本身中管理它(就像在您的示例中您将线程命名为“ThreadB”)。在这种情况下,您:
A) 可能会给它一个更有用的名称以用于调试目的
B) 强制将该名称用于该类的所有实例(除非您忽略它是一个线程的事实并对其执行上述操作,就好像它是一个 Runnable 但无论如何我们在这里讨论的是约定所以可以忽略我感觉到的这种可能性)。
例如,您甚至可以获取其创建的堆栈跟踪并将其用作线程名称。这可能看起来很奇怪,但取决于代码的结构,它对于调试目的非常有用。
这似乎是一件小事,但是您有一个非常复杂的应用程序,其中有很多线程,并且突然之间事情“停止了”(可能是由于死锁的原因,也可能是因为网络协议中的缺陷会更少显而易见 - 或其他无穷无尽的原因)然后从 Java 获取堆栈转储,其中所有线程都称为 'Thread-1'、'Thread-2'、'Thread-3' 并不总是很有用(这取决于你的线程如何结构化以及您是否可以通过堆栈跟踪有效地判断哪个是哪个 - 如果您使用的多个线程组都运行相同的代码,则并不总是可能的)。
话虽如此,您当然也可以通过创建线程类的扩展来以通用方式执行上述操作,该扩展将其名称设置为其创建调用的堆栈跟踪,然后将其与您的 Runnable 实现而不是标准的 java Thread 类一起使用(见下文),但除了堆栈跟踪之外,可能还有更多特定于上下文的信息,这些信息在线程名称中对调试很有用(对它可以处理的许多队列或套接字之一的引用,例如在这种情况下,您可能更喜欢专门针对这种情况扩展 Thread ,以便您可以让编译器强制您(或使用您的库的其他人)传递某些信息(例如,有问题的队列/套接字)以用于名称)。
下面是一个以调用堆栈跟踪为名称的通用线程示例:
public class DebuggableThread extends Thread {
private static String getStackTrace(String name) {
Throwable t= new Throwable("DebuggableThread-"+name);
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(os);
t.printStackTrace(ps);
return os.toString();
}
public DebuggableThread(String name) {
super(getStackTrace(name));
}
public static void main(String[] args) throws Exception {
System.out.println(new Thread());
System.out.println(new DebuggableThread("MainTest"));
}
}
这是比较两个名称的输出示例:
Thread[Thread-1,5,main]
Thread[java.lang.Throwable: DebuggableThread-MainTest
at DebuggableThread.getStackTrace(DebuggableThread.java:6)
at DebuggableThread.<init>(DebuggableThread.java:14)
at DebuggableThread.main(DebuggableThread.java:19)
,5,main]