当我们可以通过实现 Runnable 并将其传递给 Thread 构造函数来实现相同的功能时,允许用户通过扩展 Thread 类来创建线程的本质是什么。
6 回答
从历史的角度来看,您需要了解Thread
API 是在 Java 1.0 中设计的,在 Java 支持匿名内部类之前。很多早期的示例代码都显示了Thread
. 直到后来:
- 他们增加了对匿名内部类的支持(Java 1.1)
- 他们发现最好使用内部类(等)来提供
Runnable
实例 - 他们为任务执行、线程池等(Java 5.0)实现了标准类。
说“.Net 中的 Thread 类被标记为 final”很好,但你必须意识到 C# / .Net 在几年后出现......并且能够从 Java 的设计中学习。Java 曾经/被许多不太完美的设计决策的历史包袱困住了……因为不破坏旧代码的压倒一切的必要性。
通过实现 Runnable 实现相同的功能并将其传递给 Thread 构造函数
扩展 Thread 的使用不仅限于 Runnable。例如,您可以更改某些方法的行为或添加您自己的线程本地信息(始终使用 访问Thread.currentThread()
)。
Thread
不寻常之处在于它可以引用Runnable
to run,但它本身也是Runnable
. 默认情况下,Thread
将使用自己作为Runnable
实例来运行,当然你可以将它指向其他地方。
我认为这不是标记Thread
final 并需要 externalRunnable
或使其Thread
可扩展并拥有它自己的Runnable
. 这两种方法都非常好,而且似乎都不是比另一种更好的选择。
如果我不得不猜测,使Thread
子类化的原因是它允许您编写如下代码:
Thread t = new Thread() {
public void run() {
/* ... your code here ... */
}
};
这比创建一个子类Runnable
然后将其包装在一个线程中要干净一些。类似地,您可以对 of 进行子类化Thread
以获得Runnable
明确表明它应该用作线程的 a。当然,这主要是一个美学问题,如果 Java 设计者采取相反的方式,我认为这将是一个非常好的决定。
线程类描述线程如何运行,Runnable 描述运行什么。如果要修改运行的内容,则应实现 Runnable。如果你想修改线程的运行方式,你可以从 Thread 派生。如果您想修改线程的运行方式,您可以从 Thread 派生并实现一个单独的 Runnable 对象。
如果我可以添加一些东西,通过扩展Thread
你可以拥有线程的扩展功能(它不存在,Runnable
因为它只包含run()
方法),比如允许你的线程充当守护线程(就像垃圾收集器守护线程一样) . 其他线程存在,例如调用类的main方法的单个非守护线程(当 JVM 启动时)。
该Runnable
接口允许您的类作为线程激活(通过实现run()
方法)。
我能想到的唯一好处是:如果你扩展 Thread 类,它会让你的 run() 方法被标记为受保护。实现 Runnable的一个缺点是你的 run 方法必须被标记为 public。