Кажется, что все здесь думают, что реализация Runnable - это путь, и я на самом деле не согласен с ними, но, на мой взгляд, есть причина для расширения Thread, на самом деле вы как бы продемонстрировали это в своем коде.
Если вы реализуете Runnable, то класс, реализующий Runnable, не будет контролировать имя потока, это вызывающий код, который может установить имя потока, например:
new Thread(myRunnable,"WhateverNameiFeelLike");
но если вы расширяете Thread, то вы можете управлять этим внутри самого класса (как в вашем примере вы называете поток ThreadB). В этом случае вы:
A) может дать ему более полезное имя для целей отладки
B) принуждают использовать это имя для всех экземпляров этого класса (если вы не игнорируете тот факт, что он является потоком, и делаете вышеизложенное с ним, как будто он является Runnable, но мы говорим здесь об условном обозначении в любом дело, поэтому я могу игнорировать эту возможность, я чувствую).
Вы можете даже, например, взять трассировку стека его создания и использовать его в качестве имени потока. Это может показаться странным, но в зависимости от структуры вашего кода это может быть очень полезно для целей отладки.
Это может показаться незначительным, но если у вас очень сложное приложение с большим количеством потоков и все внезапно «остановилось» (либо по причине тупиковой ситуации, либо, возможно, из-за ошибки в сетевом протоколе, которая было бы менее очевидно - или по другим бесконечным причинам), тогда получение дампа стека из Java, где все потоки называются «Thread-1», «Thread-2», «Thread-3», не всегда очень полезно (это зависит от того, как ваши потоки структурированы и можете ли вы с пользой определить, что есть что, просто по их трассировке стека - это не всегда возможно, если вы используете группы из нескольких потоков, выполняющих один и тот же код).
Сказав, что вы, конечно, также можете сделать вышеупомянутое универсальным способом, создав расширение класса потока, которое устанавливает его имя в виде трассировки стека его вызова создания, а затем использует это с вашими реализациями Runnable вместо стандартного Класс потока Java (см. ниже), но в дополнение к трассировке стека может быть более специфичная для контекста информация, которая будет полезна в имени потока для отладки (ссылка на одну из множества очередей или сокетов, которые он может обработать, например, в этом случае вы может предпочесть расширить 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]