Extends Thread 还是 implements Runnable:如何不在面试中翻车

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

implements Runnable vs extends Thread:为什么 90% 的 Java 开发者会犯错?

\n\n

想象一下:你正在一家大型 IT 公司面试。面试官微笑着问了一个“简单”的问题:“在 Java 中,implements Runnable 和 extends Thread 有什么区别?”。看起来有什么难的呢?但根据 Stack Overflow 的数据,即使是经验丰富的开发者也会在这里栽跟头。成千上万的浏览量,数百条评论——“Java Runnable vs Thread” 这个话题依然是最热门的话题之一。

\n\n

在这篇文章中,我们不仅会列出区别。我们还将分析五大真实错误,这些错误是程序员常犯的,并展示如何编写干净、可扩展的多线程代码。如果你用 Java 编程并且直接使用 Thread——请仔细阅读。也许你并没有意识到自己正在制造问题。

\n\n

快速入门:什么是 Thread 和 Runnable?

\n\n

在深入探讨之前,让我们先回顾一下基础知识。Java Thread 是一个代表执行流的类。它能够并行运行代码。Runnable 是一个函数式接口,只有一个方法 run()。它描述了一个需要执行的任务,但不知道如何启动它。

\n\n

这是一个使用 extends Thread 的经典示例:

\n\n
public class MyThread extends Thread {\n    @Override\n    public void run() {\n        System.out.println("线程正在运行: " + Thread.currentThread().getName());\n    }\n\n    public static void main(String[] args) {\n        MyThread t = new MyThread();\n        t.start(); // 启动新线程\n    }\n}
\n\n

以下是使用 implements Runnable 实现相同功能的代码:

\n\n
public class MyTask implements Runnable {\n    @Override\n    public void run() {\n        System.out.println("任务正在执行: " + Thread.currentThread().getName());\n    }\n\n    public static void main(String[] args) {\n        Thread t = new Thread(new MyTask());\n        t.start();\n    }\n}
\n\n

乍一看,区别很小。但魔鬼,一如既往,藏在细节中。

\n\n

使用 Thread 和 Runnable 时的五大常见错误

\n\n

错误 #1:在需要 Runnable 的地方继承了 Thread

\n\n

最常见的问题是与 Thread 类的强耦合。当你写 extends Thread 时,你的类就变成了一个线程。你失去了继承其他类的可能性。Java 是单继承语言,这是一个严重的限制。

\n\n

糟糕代码示例:

\n\n
public class DataProcessor extends Thread {\n    // 已经不能再 extends JFrame、ArrayList 或其他有用的类了\n    @Override\n    public void run() {\n        // 数据处理\n    }\n}
\n\n

正确做法: 使用 implements Runnable。这是一个接口——你可以在任何已经继承了其他东西的类中实现它。

\n\n
public class DataProcessor extends BaseService implements Runnable {\n    @Override\n    public void run() {\n        // 数据处理\n    }\n}
\n\n

错误 #2:混淆 run() 和 start()

\n\n

经典错误。新手(以及不仅仅是新手)经常调用 run() 而不是 start()。区别至关重要:start() 创建一个新线程并在其中调用 run()。而 run() 则在当前线程中执行,就像一个普通方法。

\n\n

错误示例:

\n\n
Thread t = new Thread(new MyTask());\nt.run(); // 代码能运行,但在同一个线程中!没有多线程。
\n\n

控制台输出将在主线程 main 中,而不是在新线程中。这个错误很难察觉,因为代码不会崩溃——它只是没有按你期望的方式运行。

\n\n

如何避免: 始终使用 start() 来启动新线程。如果你不确定

博客

书籍推荐