为什么java中的java.lang.Thread类没有被设计者标记为final?
当我们可以通过实现Runnable来实现相同的功能并将其传递给线程构造函数时,允许用户通过扩展thread类来创建线程的本质是什么。为什么java中的java.lang.Thread类没有被设计者标记为final?,java,multithreading,language-design,runnable,library-design,Java,Multithreading,Language Design,Runnable,Library Design,当我们可以通过实现Runnable来实现相同的功能并将其传递给线程构造函数时,允许用户通过扩展thread类来创建线程的本质是什么。thread是不寻常的,因为它可以引用Runnable来运行,但它本身也是可运行的。默认情况下,线程将使用自身作为要运行的可运行实例,当然您可以将其指向其他地方 我认为这不是一个很好的理由来标记Threadfinal并要求一个外部Runnable,或者使Thread可扩展并使其成为自己的Runnable。这两种方法都非常好,而且两种方法都不是比另一种更好的选择 如果
thread
是不寻常的,因为它可以引用Runnable
来运行,但它本身也是可运行的。默认情况下,线程
将使用自身作为要运行的可运行
实例,当然您可以将其指向其他地方
我认为这不是一个很好的理由来标记Thread
final并要求一个外部Runnable
,或者使Thread
可扩展并使其成为自己的Runnable
。这两种方法都非常好,而且两种方法都不是比另一种更好的选择
如果我不得不猜测的话,将线程
子类化的原因是它允许您编写如下代码:
Thread t = new Thread() {
public void run() {
/* ... your code here ... */
}
};
这比创建Runnable
的子类,然后将其包装到线程中稍微干净一些。类似地,您可以对线程
进行子类化,以获得一个可运行的
,它清楚地表明它应该用作线程。当然,这主要是一个美学问题,如果Java设计人员采取相反的做法,我认为这将是一个完美的决定
通过以下方式实现相同的功能:
实现Runnable并将其传递给
线程构造函数
扩展线程的使用不限于Runnable。例如,您可以添加或添加自己的线程本地信息(总是可以通过
thread.currentThread()
访问)。如果我可以添加一些内容,通过扩展thread
您可以拥有线程的扩展功能(该功能在Runnable
中不存在,因为它只包含run()
方法)比如允许线程充当守护进程线程(就像垃圾收集器守护进程线程一样)。其他线程的存在类似于单个非守护进程线程,该线程调用类的主方法(当JVM启动时)
Runnable
接口允许类作为线程激活(通过实现run()
方法)。从历史的角度来看,您需要了解thread
API是在Java支持匿名内部类之前,在Java 1.0中设计的。许多早期的示例代码显示了线程的子类化。直到后来:
- 他们增加了对匿名内部类的支持(Java1.1)
- 他们发现最好使用内部类(etc)来提供
Runnable
实例
- 他们实现了用于任务执行、线程池等的标准类(Java5.0)
说“.Net中的线程类被标记为final”是很好的,但您必须意识到C#/.Net是在若干年后出现的。。。并且能够从Java的设计中学习。Java曾经/正在被一些不太完美的设计决策的历史包袱所困扰。。。因为一个最重要的命令是不要破坏旧代码。thread类描述线程如何运行,Runnable描述运行的内容。如果要修改正在运行的内容,应该实现Runnable。如果要修改线程的运行方式,请从线程派生。在需要修改线程运行方式的情况下,可以从线程派生并实现一个单独的可运行对象 我能想到的唯一一件好事是:如果扩展Thread类,它会让run()方法被标记为受保护。实现Runnable的一个缺点是你的run方法必须被标记为public。它在语法上更干净,但在设计上不干净,并且在卸载当前类加载器(例如在app server中)时可能会产生残酷的影响(perm gen leak)。@Piotr、类垃圾和所有静态jazz,不幸的是,仅仅不重写线程并不能解决这个问题,即使在死线程上,CCL也是作为引用保留的,这本身就可能造成足够的伤害。inheritedAccessControlContext和runnable保留在正在运行的线程上,因此imo.overriding线程有一些含义,比如跟踪危险的线程子类(例如override get/setContextClassLoader()),这会导致一些额外的操作和同步<代码>线程.iscloverridden(类)