从我在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,但如果您在Java5或更高版本上运行,则不应该使用新线程启动它,而是使用ExecutorService。有关详细信息,请参阅:如何在Java中实现简单线程。

其他回答

故事的寓意:

仅当您想要覆盖某些行为时才继承。

或者更确切地说,它应该被理解为:

继承更少,接口更多。

随着Java8的发布,现在有了第三个选项。

Runnable是一个函数接口,这意味着可以使用lambda表达式或方法引用创建它的实例。

您的示例可以替换为:

new Thread(() -> { /* Code here */ }).start()

或者如果要使用ExecutorService和方法引用:

executor.execute(runner::run)

这些不仅比示例要短得多,而且还具有其他答案中所述的使用Runnable over Thread的许多优点,例如单一责任和使用组合,因为您没有专门处理线程的行为。如果您只需要一个Runnable,那么这种方法也可以避免创建一个额外的类。

有一件事我很惊讶,还没有提到,那就是实现Runnable使您的类更加灵活。

如果你扩展了线程,那么你正在做的动作总是在一个线程中。然而,如果你实现了Runnable,那就不必了。你可以在一个线程中运行它,或者将它传递给某种类型的执行器服务,或者将其作为一个任务在一个单线程应用程序中传递(可能稍后运行,但在同一个线程内)。如果只使用Runnable,则选项比将自己绑定到Thread时开放得多。

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

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

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

可运行,因为:

为可运行的实现以扩展另一类将代码与处决允许您运行可从线程池运行事件线程,或以任何其他方式未来。

即使你现在不需要这些,你将来也可以。由于重写线程没有好处,Runnable是一个更好的解决方案。