我正在阅读有关主题“实现runnable vs extend thread”的一些文章,我确实理解实现runnable是首选,因为在Java中你不能有多重继承。我还阅读了一些文章说当你使用run()
方法时它只是执行当前线程中的代码,当你使用start()
时它会创建新线程,我觉得更好,但它取决于。但我仍然感到困惑,为什么你应该在课堂上实现Runnable?为什么需要?还是扩展线程?您可以创建匿名线程并在不实现runnable或任何内容的情况下启动它。
匿名线程的示例代码,未实现或扩展
new Thread() {
public void run() {
System.out.print("Example");
}
}.start();
编辑:经过一些回答和评论,我认为我不明白的内容有点澄清。我实际上不知道实现Runnable的原因,如果它的run方法没有创建新的Thread。但是很多人告诉我你可以使用这样的东西
新主题(新的Runnable())
所以最后我想知道 - 这里的代码,是否创建了一个新的Thread并在run方法中执行代码?
答案 0 :(得分:2)
非常always
实施Runnable
或Callable
您永远不应该在正常案例中直接需要子类Thread
。
如果你确实需要Thread
类的专门行为,你要么知道你正在做什么以及为什么你需要Thread
类的不同行为,或者你是在路上超过你的头脑。
对于大多数情况,您应该使用Executors
并围绕它们进行管道处理,而不是在处理多个Threads
及其交互和管理时自行滚动。
您永远不应该创建新的Thread
并管理其生命周期,容易出错且难以管理,依靠Executors
并利用它们。
答案 1 :(得分:1)
当您处理自己的类层次结构时,您不希望首先从Thread
类开始。 Thread
类是运行Runnable
的基础结构。还有更多,例如Executor
等等Thread
保持其特定于其API的状态。 Runnable
是一种方便(和适当)的方式来包装处理逻辑并将其与周围的应用程序隔离开来。
答案 2 :(得分:1)
这取决于您的要求,但一般来说,分开应该做什么?来自谁做到了?。
Thread
可以执行代码,但它有一个生命周期,一旦完成,就无法再次启动相同的Thread
实例。
Runnable
只是一些可以执行的代码或run()
。实现Runnable
的对象的生命周期不一定与线程的生命周期绑定,这给您带来了很大的好处:
Runnable
实例。如果您想重新运行Runnable
,只需创建一个Thread
,将Runnable
传递给线程的构造函数并调用start()
。Runnable
实例可以轻松重新运行,因此实例可以记住之前运行的状态。Runnable
实例可以并行运行多个线程。答案 3 :(得分:1)
为什么要在类中实现Runnable?
实现任何接口的唯一方法是定义一个类。以下是docs on Java interfaces。
为什么需要?或者扩展Thread?
如果您想直接使用Thread
,则需要执行其中一项操作。正如其他人所指出的那样,您应该查看提供线程池支持的ExecutorService
类,并隐藏用户的Thread
内容。这是tutorial on the subject。
您可以创建匿名线程并在不实现runnable或任何内容的情况下启动它。
您的代码是一个扩展Thread
的匿名类。正如Ishtar所提供的,如果有问题,这里是docs about anonymous classes。如果您从代码示例中查看Java编译器生成的.class
文件,您会看到类似Main.class
和Main$1.class
的内容。 Java实际上是在为您创建一个类。
您还可以使用implements Runnable
:
new Thread(new Runnable() {
public void run() {
System.out.print("Example");
}
}).start();
但是,您使用匿名类是否与实现Runnable
或扩展Thread
的问题正交是更好的机制来定义您的线程任务。对于这个问题,正如@MiserableVariable指出的那样,Jon Skeet's answer仍然非常重要。
答案 4 :(得分:0)
当你调用run()
方法时,它是在同一线程而不是新线程上的方法调用。如果您希望在单独的线程上发生某些事情,则需要extend Thread
(或)implement Runnable
并在线程对象上调用start()
。 Java thread life cycle可以让您清楚地了解调用run()和start()
答案 5 :(得分:-1)
匿名类很有用,但在大多数情况下都不适用。这与Thread
类一样,对于任何其他类型的类都是如此。
例如,在需要Thread对象的多个实例化并且Thread对象也具有状态(例如,一些计算结果)或与其他对象(例如,通过队列)通信的情况下,必须扩展Thread
类,或实现Runnable
接口,然后使用Thread
构造函数实际启动线程。
此主题已经过广泛讨论,因此您可以查看发布到earlier StackOverflow question或许多其他类似答案的答案(和链接)。
答案 6 :(得分:-1)
引用关于并发的Oracle文档。
第一个使用Runnable对象的习语更为通用, 因为Runnable对象可以继承Thread以外的类。 第二个习语在简单的应用程序中更容易使用,但是 受到任务类必须是后代的限制 线。本课重点介绍第一种分离方法 执行任务的Thread对象的Runnable任务。不只 这种方法更灵活,但它适用于高级别 线程管理API稍后介绍。
请注意,第一个成语是Runnable,第二个成语是从Thread扩展。看起来灵活性是实施 Runnable 方法而非扩展线程的主要动力。我非常怀疑他们是否都通过JVM映射到不同的实现(虽然我无法确认)。