从我在Java中使用线程的时间来看,我发现了两种编写线程的方法:

使用可运行的机具:

public class MyRunnable implements Runnable {
    public void run() {
        //Code
    }
}
//Started with a "new Thread(new MyRunnable()).start()" call

或者,使用扩展线程:

public class MyThread extends Thread {
    public MyThread() {
        super("MyThread");
    }
    public void run() {
        //Code
    }
}
//Started with a "new MyThread().start()" call

这两个代码块有什么显著的区别吗?


当前回答

这在Oracle的“定义和启动线程”教程中进行了讨论:

你应该使用这些成语中的哪一个?第一个成语,使用Runnable对象更一般,因为Runnable对象可以子类线程以外的类。第二个成语更容易使用在简单的应用程序中,但受限于您的任务类必须是线程的后代。本课重点介绍第一节方法,它将Runnable任务与Thread对象分离执行任务的。这种方法不仅更加灵活,而且它适用于所涵盖的高级线程管理API后来

换句话说,实现Runnable将在类扩展线程以外的类的情况下工作。Java不支持多重继承。此外,在使用某些高级线程管理API时,无法扩展线程。扩展Thread的唯一方案是在一个将来不会更新的小应用程序中。实现Runnable几乎总是更好的,因为随着项目的增长,它更加灵活。设计更改不会产生重大影响,因为您可以在java中实现许多接口,但只能扩展一个类。

其他回答

您希望实现接口而不是扩展基类的一个原因是您已经在扩展其他类。您只能扩展一个类,但可以实现任意数量的接口。

如果扩展Thread,基本上就是防止逻辑被除“this”之外的任何其他线程执行。如果您只希望一些线程执行您的逻辑,那么最好只实现Runnable。

我们可以重新访问我们希望我们的类表现为线程的基本原因吗?根本没有理由,我们只是想执行一个任务,最有可能是在异步模式下,这恰恰意味着任务的执行必须从我们的主线程和主线程分支,如果提前完成,可能会或可能不会等待分支路径(任务)。

如果这就是全部目的,那么我在哪里看到需要专门的线程。这可以通过从系统的线程池中提取一个RAW线程并分配给它我们的任务(可能是我们类的一个实例)来完成,就是这样。

因此,让我们遵循OOP概念,编写一个所需类型的类。做事有很多方法,用正确的方式做事很重要。

我们需要一个任务,所以写一个可以在线程上运行的任务定义。所以使用Runnable。

始终记住,机具专门用于传递行为,扩展用于传递特性/属性。

我们不希望线程的属性,而是希望我们的类作为一个可以运行的任务。

如果你想分开你的关注点,比如,如果你想创建任务,而谁是处理你任务的工作人员对你来说无关紧要,那么使用Runnable并将你的工作定义为任务。就像使用executor服务一样,您以Runnable/callable的形式定义任务,并将它们交给executor,然后由executor负责。

如果您想自己创建一个工作线程并将任务分配给该工作线程,那么您需要对工作线程进行更多的控制,然后使用thread类。

我想说还有第三种方法:

public class Something {

    public void justAnotherMethod() { ... }

}

new Thread(new Runnable() {
   public void run() {
    instanceOfSomething.justAnotherMethod();
   }
}).start();

也许这受到了我最近大量使用Javascript和Actionscript 3的影响,但是这样你的类就不需要实现一个非常模糊的接口,比如Runnable。

我会说实际任务与线程分离。在Runnable的情况下,我们可以将任务传递给线程、执行器框架等,而通过扩展Thread任务则与线程对象本身耦合。在扩展线程的情况下,无法执行任务隔离。这就像我们将任务烧成线程对象,就像IC芯片一样(更具体地说,不会得到任务的任何句柄)。