实现Runnable与扩展线程

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

这样,您可以计算( 什么 )与执行( 何时和/或如何 )分离。

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

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

使用Runnable / Callable可以更直接地使用Threads。

实际要点是,在任何可疑案例中,工具总是优先于延伸。

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

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

许多问题刚刚停止发生(混淆多重inheritance情况,时间浪费重构层次结构,倾向于拥有“受保护”变量,然后想知道为什么它们在当前类中没有更改它们时会发生变化,链接构造函数的需求,搞清楚不同的inheritance树如何相互作用,……

似乎每3年(过去20年),我认为我真的“得到”编程并回顾3年前我做的愚蠢事情……这是其中一例(但距离接近7年)以前在这一点上)

因为IS-A真的不是你想要的。 你的class级想要成为Runnable,但是IS-A Thread感觉太强了。 这就是inheritance所说的。 你真的只想实现run()方法,而不是Thread类中的所有其他注意事项。

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

在inheritance层次结构中扩展Thread可能没有任何意义。 如果要修改Thread的function,只需扩展Thread

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

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

  • 在顺序上下文中减少开销 ( 来源 )

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

来源: 博客 – 我不太确定这是否正确

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

首先回答这个问题:

如果扩展线程,则类(扩展线程)的实例将始终调用超类线程的构造函数。 所以MyClass myclass = new MyClass()将始终在MyClass的构造函数中调用“super()”来实例化一个线程,最后你可以在你的类中实现一些开销(如果你不使用超类的任何方法)线)。 因此,仅实现Runnable可以让您的类运行更快,而不会有任何inheritance的开销。

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

现在我只扩展了一些清楚而明显地通过“is-a”测试的东西,其他一切都是一个接口……

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

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

错了,每当你调用一个类的构造函数时,你都会得到一个自己的对象,它的扩展位置或实现方式无关紧要!

结论:在java中,每个类实例都是一个对象,并扩展了Object类(虽然基元不是……只有像int []类这样的基元数组扩展了Object,而且这样的数组具有与任何对象相同的方法 – 但是saavly他们在Javadoc中没有被提及!太阳人可能不希望我们使用它们。

顺便说一句,inheritance至少有两个优点:代码共享和清晰的Javadoc。 因为如果从类inheritance,则可以在Javadoc中看到所有子类。 您也可以使用界面执行此操作,但之后您无法共享代码。 更重要的是,你需要创建“嵌套”对象并调用两个或更多对象的构造函数而不是只有一个,这又意味着你要从超类Object本身实现一些开销! 因为Java中没有对象没有开销,并且创建尽可能少的对象对于高性能应用程序非常重要。 物体是最好的东西,但不必要的物体不是……