关于java:实现Runnable与扩展Thread

Implementing Runnable vs. extending Thread

本问题已经有最佳答案,请猛点这里访问。

为什么实现runnable比从线程类扩展更好?


实际需要解决的问题是,在任何有问题的情况下,工具总是首选于扩展。

扩展将两个类文件绑定得非常紧密,可能会导致一些代码处理非常困难。

当我第一次"理解"OO编程时,我扩展了所有东西,但它把我的整个设计变成了糊状。现在我只扩展了几个明显通过了"is-a"测试的东西,其他的东西都是一个接口…

许多问题刚刚停止发生(混淆了多个继承情况,浪费了时间重构层次结构,倾向于有"受保护"的变量,然后想知道当您在当前类中没有更改它们时,为什么它们会发生更改,链接构造函数的需求,弄清楚不同的继承树如何与彼此,…

似乎每三年(过去的20年)我都会觉得自己真的"得到"了编程,并且回顾了三年前我羞愧地做的蠢事……这就是其中的一个例子(但从近7年前的这一点来看)


这样可以将计算(what)与执行(when和/或how)分离。

例如,使用RunnableCallable时,您可以向Executor提交许多工作/计算,后者将负责安排工作。以下是ExecutorService的摘录:

1
2
3
4
5
6
7
pool = Executors.newFixedThreadPool(poolSize);
...
pool.execute(new Handler(serverSocket.accept()));
...
class Handler implements Runnable {
    ...
 }

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


因为IS-A真的不是你想要的。您的类希望能够运行,但IS-A线程感觉太强。继承就是这么说的。您只需要实现run()方法,而不是线程类中的所有其他attendent方法。

这符合Scott Meyers在"更有效的C++"中提出的非常好的建议:使非叶类抽象化。替换接口,您就可以使用了。


您可能更喜欢实现可运行的接口来扩展类线程的原因如下:

  • 减少后续上下文中的开销(源代码)

When you extends Thread class, each of your thread creates unique
object and associate with it. When you implements Runnable, it shares
the same object to multiple threads.

资料来源:博客-我不太确定这是否正确

  • 可以通过可运行的网络发送任务(线程不可序列化,源)
  • 更好的OOP风格
    • 很可能你没有"是"的关系
    • 您有可能扩展其他类(Java没有多重继承)

在继承层次结构中,扩展Thread可能没有任何意义。仅当您希望修改Thread的功能时,才扩展Thread

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


首先回答问题:

如果扩展线程,类(扩展线程)的实例将始终调用超类线程的构造函数。所以myClass myClass=新建myClass()将始终在实例化线程的MyClass的构造函数内调用"super()",最后,您可能会在类中实现一些开销(如果不使用超类线程的任何方法)。因此,只实现runnable允许类更快地运行,而不需要任何继承的开销。

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

Now I extend just the few things that clearly and obviously pass the"is-a" test and everything else is an interface...

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

When you extends Thread class, each of your thread creates unique object and associate with it. When you implements Runnable, it shares the same object to multiple threads.

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

结论:在Java中,每个类实例都是一个对象,并且扩展类对象(而基元不是)。只有INTIN[IN]类的原语数组扩展了对象,这样的数组具有与任何对象相同的方法,但遗憾的是它们没有在JavaDoc中提到。太阳人可能不想让我们用它们)。

顺便说一句,继承至少有两个优点:代码共享和清晰的javadoc。因为如果从类继承,您可以看到JavaDoc中的所有子类。你也可以通过一个接口来实现,但是你不能共享代码。更重要的是,您将需要创建"嵌套"对象,并调用两个或多个对象的构造函数,而不是只调用一个,这再次意味着您将从超类对象本身实现一些开销!因为Java中没有对象,没有开销,尽可能少地创建对象对于高性能应用来说是非常重要的。物体是最伟大的,但不必要的物体不是…