1. 引言

"到底该实现 Runnable 还是继承 Thread?" 这个问题在 Java 开发中经常被讨论。

本文将通过实际场景分析两种方式的优劣,帮你避开常见误区,选择更合适的方案。

2. 使用 Thread 类

先来看继承 Thread 的实现方式:

public class SimpleThread extends Thread {

    private String message;

    // 标准日志记录器和构造器

    @Override
    public void run() {
        log.info(message);
    }
}

启动这种线程有两种方式:

2.1 直接启动

@Test
public void givenAThread_whenRunIt_thenResult()
  throws Exception {
 
    Thread thread = new SimpleThread(
      "SimpleThread executed using Thread");
    thread.start();
    thread.join();
}

2.2 通过线程池启动

@Test
public void givenAThread_whenSubmitToES_thenResult()
  throws Exception {
    
    executorService.submit(new SimpleThread(
      "SimpleThread executed using ExecutorService")).get();
}

⚠️ 注意:这种方式的缺点很明显:

  • 为了执行简单日志操作就写了这么多代码
  • SimpleThread 无法继承其他类(Java 不支持多继承)

3. 实现 Runnable 接口

现在改用实现 Runnable 的方式:

class SimpleRunnable implements Runnable {
    
    private String message;
    
    // 标准日志记录器和构造器
    
    @Override
    public void run() {
        log.info(message);
    }
}

这个 SimpleRunnable 只是个任务单元,有多种执行方式:

3.1 通过 Thread 类执行

@Test
public void givenRunnable_whenRunIt_thenResult()
 throws Exception {
    Thread thread = new Thread(new SimpleRunnable(
      "SimpleRunnable executed using Thread"));
    thread.start();
    thread.join();
}

3.2 通过线程池执行

@Test
public void givenARunnable_whenSubmitToES_thenResult()
 throws Exception {
    
    executorService.submit(new SimpleRunnable(
      "SimpleRunnable executed using ExecutorService")).get();
}

关于 ExecutorService 的详细用法可参考 Java 线程池教程

3.3 Java 8+ 的 lambda 写法

从 Java 8 开始,Runnable 作为函数式接口可以直接用 lambda 表达式:

@Test
public void givenARunnableLambda_whenSubmitToES_thenResult() 
  throws Exception {
    
    executorService.submit(
      () -> log.info("Lambda runnable executed!"));
}

4. 对比分析:Runnable 还是 Thread?

简单粗暴地总结:优先使用 Runnable,原因如下:

设计原则更合理

  • 继承 Thread 时,我们实际是在重写 Runnable 的方法(Thread 实现了 Runnable),这违反了 IS-A 原则
  • 实现 Runnable 采用组合而非继承,扩展性更强

避免继承限制

  • 继承 Thread 后无法再继承其他类
  • 实现 Runnable 不影响继承体系

现代 Java 特性支持

  • Java 8+ 可用 lambda 表达式简化代码
  • 更符合函数式编程思想

继承 Thread 的坑

  • 线程管理与业务逻辑耦合
  • 难以复用线程资源
  • 违背"组合优于继承"原则

5. 总结

通过对比可以清晰看出:

  • 实现 Runnable 是更优雅的方案
  • 继承 Thread 仅在特殊场景下适用(如需要操作 Thread 特有方法时)
  • 现代开发中建议结合线程池 + lambda 使用 Runnable

本文代码示例可在 GitHub 仓库 获取完整实现


原始标题:Implementing a Runnable vs Extending a Thread