实现 Runnable 与扩展 Thread [重复]

Posted

技术标签:

【中文标题】实现 Runnable 与扩展 Thread [重复]【英文标题】:Implementing Runnable vs. extending Thread [duplicate] 【发布时间】:2011-02-16 11:40:02 【问题描述】:

为什么实现 Runnable 比从 Thread 类扩展更好?

【问题讨论】:

【参考方案1】:

先回答问题:

如果你扩展线程,你的类的一个实例(扩展线程)将总是调用超类线程的构造函数。所以 我的班级 myclass= 新的我的班级() 将始终在实例化线程的 MyClass 的构造函数中调用“super()”,最后您可能会在您的类中实现一些开销(如果您不使用超类线程的任何方法)。所以只实现 Runnable 可以让你的类运行得更快,而没有任何继承开销。

此外,这里还有一些错误的答案:

现在我只扩展了少数清楚且明显通过“is-a”测试的东西,其他一切都是接口......

你没有考虑过创建一个没有任何接口的对象吗?因为为每个对象都实现一个接口是非常错误的!

当您扩展 Thread 类时,您的每个线程都会创建唯一的对象并与之关联。当您实现 Runnable 时,它​​会将同一个对象共享给多个线程。

错了,每次调用一个类的构造函数,都会得到一个自己的对象,不管是从哪里扩展,实现什么!

结论:在java中,每个类实例都是一个对象,并且扩展了类Object(而原语不是......只有像int []类这样的原语数组扩展了Object,等等数组具有与任何对象相同的方法 - 但遗憾的是,Javadoc 中没有提到它们!Sun 的人可能不希望我们使用它们)。

顺便说一句,继承至少有两个优点:代码共享和清晰的 Javadoc。因为如果你从一个类继承,你可以在 Javadoc 中看到所有的子类。您也可以使用界面来做到这一点,但是您不能共享代码。更重要的是,您将需要创建“嵌套”对象并调用两个或多个对象的构造函数,而不仅仅是一个,这再次意味着您从超类 Object 本身实现了一些开销!因为在 Java 中没有没有开销的对象,所以创建尽可能少的对象对于高性能应用程序非常重要。对象是最伟大的东西,但不必要的对象不是......

【讨论】:

【参考方案2】:

您可能更喜欢实现Interface Runnable 而不是扩展Class Thread 的原因如下:

更少的开销在顺序上下文中 (source)

当您扩展 Thread 类时,您的每个线程都会创建唯一的 对象并与之关联。当您实现 Runnable 时,它​​共享 同一个对象到多个线程。

来源:a blog - 我不太确定这是否正确

您可以使用 Runnable 通过网络发送任务(线程不可序列化,source) 更好的 OOP 风格 您很可能没有“是”关系 您可以扩展其他类(Java 没有多重继承)

【讨论】:

【参考方案3】:

因为 IS-A 确实不是您想要的。你的类想要 Runnable,但是 IS-A Thread 感觉太强了。这就是继承的意思。您真的只想实现 run() 方法,而不是 Thread 类中的所有其他相关内容。

这符合 Scott Meyers 在“更有效的 C++”中的非常好的建议:使非叶类抽象。替换接口就可以了。

【讨论】:

【参考方案4】:

要带走的实际要点是,在任何有问题的情况下,总是首选实现而不是扩展。

Extends 非常紧密地绑定了两个类文件,可能会导致一些非常难以处理的代码。

当我第一次“理解”面向对象编程时,我正在扩展一切,但它把我的整个设计变成了糊状。现在我只扩展了一些清楚而明显地通过“is-a”测试的东西,其他一切都是接口......

许多问题刚刚停止发生(令人困惑的多重继承情况,浪费时间重构层次结构,具有“受保护”变量的趋势然后想知道当您没有在当前类中更改它们时它们为什么会改变,对构造函数的链接要求,弄清楚不同的继承树如何相互交互,...

似乎每 3 年(过去 20 年)我认为我真的“开始”编程,并羞愧地回顾我 3 年前所做的愚蠢事情......这就是其中之一(但距离更近到 7 年前)

【讨论】:

【参考方案5】:

在继承层次结构中扩展Thread 可能没有任何意义。如果您想修改Threads 的功能,请仅扩展Thread

使用Runnable,任何继承层次结构中的任何类都可以公开一个任务,该任务可以被视为一个工作单元以让Thread 执行。

【讨论】:

【参考方案6】:

这样你解耦计算(什么)与执行(何时和/或如何强>)。

使用RunnableCallable,例如,您可以将许多工作/计算提交给Executor,该Executor 将负责安排工作。这是ExecutorService的摘录形式:

pool = Executors.newFixedThreadPool(poolSize);
...
pool.execute(new Handler(serverSocket.accept()));
...
class Handler implements Runnable 
    ...
 

使用Runnable/Callable 比直接使用线程更灵活。

【讨论】:

还可以让你的 runnable 扩展其他非线程类

以上是关于实现 Runnable 与扩展 Thread [重复]的主要内容,如果未能解决你的问题,请参考以下文章

扩展Thread类并实现Runnable接口的场景[重复]

如何使用android延迟不扩展或实现Thread或Runnable

Thread使用总结——Runnable和Thread的区别是啥

关于Thread与runnable

JAVA多线程继承Thread 与实现Runnable接口的相关疑问

Java中继承thread类与实现Runnable接口的区别