Java创建多线程需区分定义任务(重写run()/call())和执行任务(调用start());直接调用run()无并发效果;继承Thread受限于单继承,实现Runnable更灵活解耦;Callable+FutureTask适用于需返回结果的场景;start()仅能调用一次,run()执行时机由系统调度。

Java 中创建并启动多线程,核心在于区分“定义任务”和“执行任务”两个环节。直接调用 run() 只是普通方法执行,不会开启新线程;必须调用 start() 才能真正触发 JVM 创建操作系统级线程,并由其自动调用 run() 方法。
继承 Thread 类:最直观的方式
适合简单场景或教学演示,但受限于 Java 单继承机制,无法再继承其他类。
- 自定义类继承 Thread,重写 run() 方法,把要并发执行的逻辑写在里面
- 创建该子类实例后,调用 start() 启动线程(不是 run())
- 可通过 setName() 设置线程名,便于调试和日志追踪
- 示例中两个 MyThread 实例分别调用 start(),就能看到主线程与子线程交替输出
实现 Runnable 接口:更推荐的解耦方式
Runnable 只描述“做什么”,不关心“怎么执行”,职责清晰,利于复用和扩展。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 定义一个类实现 Runnable 接口,重写 run() 方法
- 将该对象传给 Thread 构造器,再调用 Thread 对象的 start()
- 支持 Lambda 表达式简化写法:
() -> System.out.println("任务执行") - 多个 Thread 可共用同一个 Runnable 实例,适合处理相同逻辑、不同数据的并发任务
使用 Callable + FutureTask:需要返回结果时的选择
当线程执行完需返回值(比如计算结果、查询响应),Runnable 的 void 返回类型就不够用了。
立即学习“Java免费学习笔记(深入)”;
- 实现 Callable<T> 接口,重写 call() 方法,可带返回值并抛出异常
- 用 FutureTask<T> 包装 Callable 对象,它本身实现了 Runnable,可交给 Thread 启动
- 线程结束后,通过 futureTask.get() 获取结果(会阻塞直到完成)
- 这是为后续接入线程池(如 ExecutorService)打基础的关键一步
启动线程的常见误区
很多初学者卡在这一步,理解偏差会导致“以为开了线程,实际还是单线程运行”。
- 绝对不要直接调用 run():它只是普通方法调用,在当前线程同步执行,毫无并发意义
- 一个线程对象只能调用一次 start(),重复调用会抛 IllegalThreadStateException
- 线程启动后,run() 的执行时机由操作系统调度决定,输出顺序不固定,不能依赖打印顺序判断逻辑先后
- 若需控制执行顺序(如等待某线程结束),要用 join(),而不是靠 sleep() 猜测时间

















