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

如果我没有错的话,它或多或少类似于

接口和抽象类之间的区别是什么?

extends建立“Is A”关系,接口提供“Has A”功能。

首选工具可运行:

如果不需要扩展Thread类并修改Thread API默认实现如果你执行的是一个火灾和忘记命令如果您已经在扩展另一个类

首选“扩展线程”:

如果必须重写oracle文档页中列出的任何线程方法

通常,您不需要重写线程行为。因此,在大多数情况下,首选实现Runnable。

另一方面,使用高级ExecutorService或ThreadPoolExecutorServiceAPI提供了更多的灵活性和控制。

看看这个SE问题:

ExecutorService vs休闲线程生成器

将Thread类与Runnable实现分离还可以避免线程和run()方法之间的潜在同步问题。单独的Runnable通常在引用和执行可运行代码的方式上提供更大的灵活性。

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

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

但是,如果您的子类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和Thread相互比较是不明智的。

这两者在多线程中具有相关性和关系,就像机动车的车轮和发动机关系一样。

我想说,多线程只有一种方法,有两个步骤。让我表明我的观点。

可运行:当实现接口Runnable时,这意味着您正在创建可在不同线程中运行的东西。现在创建可以在线程内运行的东西(可以在线程中运行)并不意味着创建线程。因此,MyRunnable类只是一个带有void run方法的普通类。它的对象将是一些普通对象,只有一个在调用时正常执行的方法运行。(除非我们在线程中传递对象)。

线程:class线程,我可以说是一个非常特殊的类,它能够启动一个新的线程,这实际上通过它的start()方法实现了多线程。

为什么不明智地进行比较?因为我们需要这两个线程来实现多线程。

对于多线程,我们需要两件事:

可以在线程内运行的东西(可运行)。可以启动新线程的东西。

因此,从技术上和理论上来说,这两个都是启动线程所必需的,一个线程将运行,另一个线程会使线程运行(就像机动车的车轮和发动机)。

这就是为什么不能使用MyRunnable启动线程,需要将其传递给thread的实例。

但是,只有使用类thread才能创建和运行线程,因为类thread实现了Runnable,所以我们都知道thread内部也是一个Runnable。

最后,Thread和Runnable是多线程的补充,而不是竞争对手或替代者。