Java中的“implements Runnable”与“extends Thread”

从我花在 线程上的时间,我发现了以下两种编写线程的方法: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

这两个代码块有什么显著差异吗?


答案 1

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

实际上,这意味着您也可以从另一个类实现和扩展...从Java 8开始,您也可以通过lambda表达式实现。RunnableRunnable


答案 2

tl;dr: 实现 Runnable 更好。但是,警告很重要

一般来说,我建议使用类似的东西,而不是因为它允许你只将你的工作与你所选择的并发性松散地结合在一起。例如,如果您使用 a,并且稍后决定这实际上不需要它自己的,则可以调用 threadA.run()。RunnableThreadRunnableThread

警告:在这里,我强烈反对使用原始线程。我更喜欢使用CallablesFutureTasks(来自javadoc:“可取消的异步计算”)。超时的集成,适当的取消和现代并发支持的线程池对我来说都比成堆的原始线程更有用。

后续工作:有一个 FutureTask 构造函数允许您使用 Runnables(如果这是您最熟悉的),并且仍然可以获得现代并发工具的好处。引用javadoc的话

如果不需要特定结果,请考虑使用以下形式的构造:

Future<?> f = new FutureTask<Object>(runnable, null)

因此,如果我们用您的 替换它们,我们将得到以下内容:runnablethreadA

new FutureTask<Object>(threadA, null)

另一个允许您更接近Runnables的选项是ThreadPoolExecutor。您可以使用 execute 方法传入 Runnable 以执行“将来某个时间的给定任务”。

如果您想尝试使用线程池,上面的代码片段将变成如下所示的内容(使用 Executors.newCachedThreadPool() 工厂方法):

ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());