什么时候应该实现Runnable?

时间:2014-01-07 21:35:03

标签: java multithreading

我正在阅读有关主题“实现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方法中执行代码?

7 个答案:

答案 0 :(得分:2)

Runnable或Callable是首选的习惯用法

非常always实施RunnableCallable您永远不应该在正常案例中直接需要子类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.classMain$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映射到不同的实现(虽然我无法确认)。