从我在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类是最好的。

最常见的区别是

当您扩展Thread类时,在此之后,您不能扩展所需的任何其他类。(如您所知,Java不允许继承多个类)。

当您实现Runnable时,您可以为您的类节省空间,以便将来或现在扩展任何其他类。

Java不支持多个继承,这意味着您只能在Java中扩展一个类,因此一旦扩展了Thread类,您就失去了机会,无法在Java中延伸或继承另一个类。在面向对象编程中,扩展类通常意味着添加新功能,以及修改或改进行为。如果我们没有对线程进行任何修改,那么请改用Runnable接口。可运行接口表示一个任务,它可以由普通线程或执行器或任何其他方式执行。因此,将Task逻辑分离为Runnable而不是Thread是一个很好的设计决策。将任务分离为可运行任务意味着我们可以重用任务,也可以通过不同的方式执行任务。因为一旦线程完成,就不能重新启动它。任务的Runnable与Thread,Runnable是赢家。Java设计器认识到这一点,这就是为什么Executors接受Runnable作为Task,并且他们有执行这些任务的工作线程。继承所有线程方法只是表示一个任务的额外开销,这可以通过Runnable轻松完成。

由javareviewed.blogspot.com提供

这是Java中Thread和Runnable之间的一些显著差异。如果您知道Thread与Runnable之间的其他差异,请通过评论分享。我个人在这个场景中使用Runnable over Thread,并建议根据您的需求使用Runnable或Callable接口。

然而,显著的区别是。

当您扩展Thread类时,每个线程都会创建一个唯一的对象并与其关联。当您实现Runnable时,它将同一对象共享给多个线程。

其他回答

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

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

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

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

线程保持不打算访问的行为;

它的同步锁用于连接等。它有一些你可以偶然访问的方法。

但是,如果您的子类Thread必须考虑实现更多Thread。

public class ThreadMain {
    public int getId() {
        return 12345678;
    }

    public String getName() {
        return "Hello World";
    }

    public String getState() {
        return "testing";
    }

    public void example() {
        new Thread() {
            @Override
            public void run() {
                System.out.println("id: "+getId()+", name: "+getName()+", state: "+getState());
            }
        }.start();
    }

    public static void main(String[] args) {
        new ThreadMain().example();
    }
}

如果你运行这个,你可能会期望

id: 12345678, name: Hello World, state: testing

然而,您并没有调用您认为是的方法,因为您使用的是Thread而不是ThreadMain中的方法,相反,您会看到类似

id: 11, name: Thread-0, state: RUNNABLE

最简单的解释是通过实现Runnable,我们可以将同一个对象分配给多个线程,并且每个线程共享相同的对象状态和行为。

例如,假设有两个线程,thread1在数组中放入一个整数,thread2在数组填满时从数组中取出整数。请注意,为了让thread2正常工作,它需要知道数组的状态,不管thread1是否已将其填满。

实现Runnable使您能够灵活地共享对象,而扩展Thread使您能够为每个线程创建新对象,因此thread1完成的任何更新都会丢失给thread2。

这也许不是答案,但无论如何;还有一种创建线程的方法:

Thread t = new Thread() {
    public void run() {
        // Code here
    }
}

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

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