一句话结论
能不用 new Thread()
就别直接用;企业级项目首选线程池,避免资源耗尽与管理混乱。
一、方式一:继承 Thread 类
示例
java
class MyThread extends Thread {
@Override
public void run() {
System.out.println("任务执行:" + Thread.currentThread().getName());
}
}
public class Demo {
public static void main(String[] args) {
new MyThread().start();
}
}
特点
-
优点:实现简单,直接继承并重写
run()
方法。 -
缺点:
- Java 单继承限制,无法再继承其他类。
- 任务和线程强耦合,任务不能复用。
- 线程创建和销毁开销大。
结论:只适合入门学习,生产代码中几乎不用。
二、方式二:实现 Runnable 接口
示例
java
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("任务执行:" + Thread.currentThread().getName());
}
}
public class Demo {
public static void main(String[] args) {
new Thread(new MyRunnable()).start();
}
}
特点
-
优点:
- 任务与线程解耦,可以复用
Runnable
对象。 - 避免单继承限制,更灵活。
- 任务与线程解耦,可以复用
-
缺点:
run()
无返回值,无法获取执行结果。
结论:实际项目常用,但当需要返回值或异常处理时局限性明显。
三、方式三:实现 Callable 接口 + Future
示例
java
import java.util.concurrent.*;
class MyCallable implements Callable<Integer> {
@Override
public Integer call() {
return 42;
}
}
public class Demo {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(new MyCallable());
System.out.println("结果:" + future.get());
executor.shutdown();
}
}
特点
-
优点:
call()
方法有返回值,可以抛出异常。- 搭配
Future
、CompletableFuture
支持异步编排。
-
缺点:
- 相比
Runnable
更复杂,需要ExecutorService
配合。
- 相比
结论:适合需要获取结果或异常处理的异步任务。
四、方式四:使用线程池(Executor 框架)
示例
java
ExecutorService pool = Executors.newFixedThreadPool(4);
for (int i = 0; i < 5; i++) {
pool.execute(() -> System.out.println(Thread.currentThread().getName() + " 执行任务"));
}
pool.shutdown();
特点
-
优点:
- 资源复用:避免频繁创建/销毁线程。
- 任务调度:队列 + 拒绝策略,适合高并发场景。
- 灵活扩展:可自定义核心线程数、最大线程数、存活时间、队列。
-
缺点:
- 使用不当可能导致队列堆积、拒绝任务或 OOM。
- 需配合监控与合理参数配置。
结论:企业级项目首选,尤其是高并发系统。
五、四种方式对比表
方式 | 返回值 | 灵活性 | 使用难度 | 适用场景 |
---|---|---|---|---|
继承 Thread | 无 | 低 | 简单 | 学习/测试 |
Runnable | 无 | 中 | 简单 | 一次性异步任务 |
Callable + Future | 有 | 高 | 中等 | 需要结果/异常处理 |
线程池 | 可选(Future) | 很高 | 较高 | 生产环境标准方案 |
六、工程实践建议
- 禁止直接 new Thread,无法控制线程数量,容易耗尽资源。
- 避免 Executors 提供的快捷工厂方法 (如
newFixedThreadPool
),因其参数不透明,可能造成隐患。推荐显式使用ThreadPoolExecutor
构造函数,明确核心参数与拒绝策略。 - 推荐使用 Callable + 线程池,既能拿到返回值,也能进行任务调度与统一管理。
- 务必优雅关闭线程池,否则可能引发内存泄漏或服务无法退出。
七、小结
- 继承 Thread:入门。
- Runnable:任务解耦,轻量。
- Callable:有返回值,实用。
- 线程池 :工程实践必选,结合
Future/CompletableFuture
更强大。