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

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


当前回答

是的:implements Runnable是首选的实现方式,IMO。你并没有真正专门研究线程的行为。你只是在给它一些东西。这意味着构图是哲学上“更纯粹”的方式。

实际上,这意味着您可以实现Runnable并从另一个类扩展。。。您还可以通过lambda表达式实现Runnable,如Java 8。

其他回答

线程和可运行线程之间的差异。若我们使用线程类创建线程,则线程数等于我们创建的对象数。如果我们通过实现可运行接口来创建线程,那么我们可以使用单个对象来创建多个线程。因此,单个对象由多个线程共享。因此,它将占用更少的内存

因此,如果我们的数据不敏感,则取决于要求。所以它可以在多个线程之间共享,我们可以使用Runnable接口。

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

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

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

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

实现Runnable和扩展Thread之间的一个区别是,通过扩展Thread,每个线程都有一个与其关联的唯一对象,而实现Runnable,许多线程可以共享同一个对象实例。

实现Runnable的类不是线程,只是一个类。对于要由线程执行的Runnable,需要创建一个Thread实例,并将Runnable实例作为目标传入。

在大多数情况下,如果只打算重写run()方法而不打算重写其他Thread方法,则应使用Runnable接口。这一点很重要,因为除非程序员打算修改或增强类的基本行为,否则类不应该被子类化。

当需要扩展超类时,实现Runnable接口比使用Thread类更合适。因为我们可以在实现Runnable接口时扩展另一个类以生成线程。但是如果我们只是扩展Thread类,我们就不能从任何其他类继承。

故事的寓意:

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

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

继承更少,接口更多。