从我在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

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


当前回答

Runnable是一个接口,而Thread是实现该接口的类。从设计的角度来看,任务的定义方式和执行方式之间应该有明确的区分。前者由Runnalbe实现负责,后者由Thread类负责。在大多数情况下,实现Runnable是正确的做法。

其他回答

线程类定义了几个可由扩展类重写的方法。但要创建线程,我们必须重写run()方法。这同样适用于Runnable。

然而,Runnable是创建线程的首选方法。主要原因如下:

由于Runnable是一个接口,因此可以扩展其他类。但如果您扩展“线程”,则该选项将消失。如果您没有修改或增强大量Thread功能,那么扩展Thread类不是首选方法。

Java不支持多重继承,所以如果您扩展Thread类,则不会扩展其他类。

例如:如果您创建一个applet,那么它必须扩展applet类,所以这里创建线程的唯一方法是实现Runnable接口

我不是专家,但我能想到实现Runnable而不是扩展Thread的一个原因:Java只支持单一继承,因此只能扩展一个类。

编辑:这原本是说“实现一个接口需要更少的资源”,但无论如何都需要创建一个新的线程实例,所以这是错误的。

由于这是一个非常流行的话题,而且好的答案到处都是,而且处理得非常深入,所以我觉得将其他人的好答案汇编成更简洁的形式是合理的,因此新来者可以很容易地概括:

通常扩展类以添加或修改功能。因此,如果不想覆盖任何线程行为,请使用Runnable。同样,如果不需要继承线程方法,那么可以通过使用Runnable来避免这种开销。单一继承:如果您扩展Thread,则不能从任何其他类扩展,因此如果这是您需要做的,则必须使用Runnable。将领域逻辑与技术手段分开是一个很好的设计,从这个意义上说,最好有一个可运行的任务将您的任务与运行者隔离开来。您可以多次执行同一个Runnable对象,但Thread对象只能启动一次。(也许是执行器接受Runnables而不接受Threads的原因。)如果您将任务开发为Runnable,那么您现在和将来都可以灵活使用它。您可以通过执行器同时运行,也可以通过线程运行。您还可以在同一线程中非并发地使用/调用它,就像其他任何普通类型/对象一样。这也使得在单元测试中分离任务逻辑和并发方面更加容易。如果你对这个问题感兴趣,你可能也会对Callable和Runnable之间的区别感兴趣。

我发现使用Runnable是最有用的,因为上面提到的所有原因,但有时我喜欢扩展Thread,这样我就可以创建自己的线程停止方法,并直接在我创建的线程上调用它。