"implements Runnable" vs "extends Thread" in Java

“implements Runnable” vs “extends Thread” in Java

技术背景

在 Java 多线程编程中,实现多线程有两种常见方式:实现 Runnable 接口和继承 Thread 类。这两种方式都能实现多线程的功能,但在使用场景、设计理念和实际应用中存在一些差异。了解它们的区别,有助于开发者根据具体需求选择合适的方式进行多线程编程。

实现步骤

实现 Runnable 接口

  1. 创建一个类实现 Runnable 接口。
  2. 重写 run() 方法,在该方法中定义线程要执行的任务。
  3. 创建该类的实例。
  4. 将该实例作为参数传递给 Thread 类的构造函数,创建 Thread 对象。
  5. 调用 Thread 对象的 start() 方法启动线程。

继承 Thread 类

  1. 创建一个类继承 Thread 类。
  2. 重写 run() 方法,在该方法中定义线程要执行的任务。
  3. 创建该类的实例。
  4. 调用该实例的 start() 方法启动线程。

核心代码

实现 Runnable 接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 实现 Runnable 接口
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Running task implemented by Runnable");
}
}

public class RunnableExample {
public static void main(String[] args) {
// 创建 MyRunnable 实例
MyRunnable myRunnable = new MyRunnable();
// 创建 Thread 对象并传入 MyRunnable 实例
Thread thread = new Thread(myRunnable);
// 启动线程
thread.start();
}
}

继承 Thread 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 继承 Thread 类
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Running task implemented by extending Thread");
}
}

public class ThreadExample {
public static void main(String[] args) {
// 创建 MyThread 实例
MyThread myThread = new MyThread();
// 启动线程
myThread.start();
}
}

最佳实践

优先选择实现 Runnable 接口

  • 可扩展性:Java 不支持多重继承,实现 Runnable 接口的类还可以继承其他类,增加了代码的灵活性。
  • 代码复用:可以将同一个 Runnable 对象传递给多个 Thread 对象,多个线程可以共享同一个任务。
  • 分离任务和执行:将任务的定义和执行分离,符合单一职责原则,提高了代码的可维护性。

使用线程池

在 Java 5 及以上版本,建议使用 ExecutorService 线程池来管理线程,而不是直接创建 Thread 对象。这样可以更好地控制线程的数量和生命周期,提高性能和资源利用率。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Running task in thread pool");
}
}

public class ThreadPoolExample {
public static void main(String[] args) {
// 创建线程池
ExecutorService executorService = Executors.newCachedThreadPool();
// 提交任务
executorService.execute(new MyRunnable());
// 关闭线程池
executorService.shutdown();
}
}

常见问题

为什么不能直接调用 run() 方法?

直接调用 run() 方法不会启动新线程,而是在当前线程中顺序执行 run() 方法中的代码。要启动新线程,必须调用 start() 方法。

继承 Thread 类有什么缺点?

  • 单继承限制:由于 Java 不支持多重继承,继承 Thread 类后就不能再继承其他类,限制了代码的可扩展性。
  • 资源浪费:每个线程都需要创建一个独立的 Thread 子类对象,可能会导致资源浪费。

实现 Runnable 接口和继承 Thread 类在资源消耗上有区别吗?

从本质上来说,两者在资源消耗上没有太大区别,因为最终都需要创建 Thread 对象来启动线程。但实现 Runnable 接口可以更好地复用任务,避免创建过多的 Thread 对象。


"implements Runnable" vs "extends Thread" in Java
https://119291.xyz/posts/implements-runnable-vs-extends-thread-in-java/
作者
ww
发布于
2025年5月15日
许可协议