面试知识库
基础

创建线程的方式#

一句话答案#

创建线程本质只有”继承 Thread”和”实现 Runnable/Callable 再交给 Thread 或线程池执行”两类,生产中应通过线程池统一管理;start() 才会真正起新线程,直接调 run() 只是普通方法调用。

核心要点

四种常见写法:

1. 继承 Thread,重写 run()

class MyThread extends Thread {
    public void run() { System.out.println("run"); }
}
new MyThread().start();
java
  • 缺点:Java 单继承,继承了 Thread 就不能再继承别的类,灵活性差

2. 实现 Runnable 接口(推荐)

Runnable task = () -> System.out.println("run");
new Thread(task).start();
java
  • 优点:任务与线程解耦,可复用、可交给线程池;类还能继承别的父类
  • 本质:Thread 也是实现了 Runnable;这是组合优于继承的体现

3. 实现 Callable + FutureTask(有返回值/能抛异常)

Callable<Integer> c = () -> 42;
FutureTask<Integer> ft = new FutureTask<>(c);
new Thread(ft).start();
Integer result = ft.get();   // 阻塞获取返回值
java

4. 线程池(生产首选)

ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> doWork());
java

严格说只有一种本质方式:

  • 不管哪种写法,最终都是把任务逻辑(run 方法体)传给 Thread 去执行
  • 继承 Thread 是重写 run,实现 Runnable 是把 run 委托给传入的对象——底层都是一个 Thread + 一个 run

start() vs run()(高频送命题):

start()run()
行为启动新线程,由 JVM 调度后回调 run当前线程直接执行 run,不开新线程
线程数多一个线程还是当前线程(串行)
重复调用同一线程 start 两次抛 IllegalThreadStateException可多次调用(就是普通方法)

Executors 几种内置线程池(常被追问):

  • newFixedThreadPool / newSingleThreadExecutor:用无界 LinkedBlockingQueue,任务堆积可能 OOM
  • newCachedThreadPool:最大线程数 Integer.MAX_VALUE,线程暴涨可能 OOM
  • 阿里规约:不推荐用 Executors,应手动 new ThreadPoolExecutor 明确队列容量和拒绝策略
面试回答(2分钟版)

创建线程通常说四种方式:继承 Thread 重写 run、实现 Runnable 接口、实现 Callable 配合 FutureTask、以及用线程池。但严格来讲本质只有一种,因为不管哪种写法最后都是把任务逻辑交给一个 Thread 对象去执行,继承 Thread 是直接重写它的 run,实现 Runnable 是把 run 委托给传进去的对象,所以更推荐 Runnable,它把任务和线程解耦、能复用、还能交给线程池,而且避免了 Java 单继承的限制。Callable 和 Runnable 的区别是它有返回值、能抛受检异常,要配合 FutureTask 用 get 拿结果。生产环境一定是用线程池,能复用线程、控制并发数。还有个经典点是 start 和 run 的区别:调 start 才会真正启动一个新线程由 JVM 调度去回调 run,而直接调 run 只是在当前线程里普通地执行一遍方法体,根本没开新线程;另外同一个线程 start 两次会抛 IllegalThreadStateException。最后线程池不建议用 Executors 的工厂方法,因为 FixedThreadPool 用无界队列、CachedThreadPool 线程数无上限,都有 OOM 风险,应该手动 new ThreadPoolExecutor。

追问与易错

追问方向:

  • “直接调用 run() 会怎样?”→ 在当前线程串行执行方法体,不会启动新线程
  • “为什么推荐 Runnable 而不是继承 Thread?”→ 避免单继承限制,任务与线程解耦可复用、可入线程池
  • “Runnable 和 Callable 的区别?”→ Callable 有返回值、可抛受检异常,配合 Future 获取结果
  • “一个线程能 start 两次吗?”→ 不能,第二次抛 IllegalThreadStateException
  • “为什么不推荐 Executors 创建线程池?”→ Fixed/Single 用无界队列、Cached 线程数无上限,都可能 OOM

易错点:

  • ❌ “线程池是第几种创建线程的全新方式”——它本质还是封装了 Thread + Runnable,只是管理方式
  • ❌ “调用 run() 也能并发”——run() 只是普通方法调用,纯串行
  • ❌ “实现 Runnable 就比继承 Thread 性能高”——区别在设计灵活性,不是性能