最简单创建线程的方式是继承thread类并重写run()方法,调用start()启动;误调run()则为同步执行。推荐实现runnable接口以解耦任务与执行者,配合线程池使用;需返回结果时用callable+future,注意get()阻塞及异常处理;线程生命周期管理不可忽视,应合理使用interrupt()、资源释放和命名。

直接用 Thread 类是最简单的方式
新建一个类继承 Thread,重写 run() 方法,然后调用 start() 启动——这是最直白的创建方式,适合逻辑简单、不需复用的场景。
注意:start() 才真正启动新线程;如果误调 run(),只是在当前线程同步执行,不会并发。
示例:
class MyThread extends Thread {
public void run() {
System.out.println("线程运行中:" + Thread.currentThread().getName());
}
}
// 使用
new MyThread().start();
- 不能多次调用
start(),否则抛IllegalThreadStateException - 子类里若需访问父类
Thread的方法(如getId()),得确保线程已启动(否则部分状态不可用) - 继承方式耦合度高,Java 不支持多重继承,后续扩展受限
实现 Runnable 接口更灵活
把任务逻辑封装进 Runnable 实现类,再传给 Thread 构造器。这种方式解耦了「任务」和「执行者」,也避免了继承限制。
立即学习“Java免费学习笔记(深入)”;
常见错误:直接 new Runnable 实现类后调用 run() —— 这仍是单线程执行,没触发并发。
示例:
Runnable task = () -> System.out.println("Lambda 任务:" + Thread.currentThread().getName());
new Thread(task).start();
- 推荐优先使用该方式,尤其配合线程池(
ExecutorService.submit(Runnable)) - 若需返回结果,
Runnable不行,得换Callable - 共享变量时要注意线程安全,
Runnable实例可能被多个Thread复用
Callable + Future 是带返回值的方案
当线程执行完要拿结果(比如计算结果、IO 响应),就得用 Callable 替代 Runnable。它允许抛异常、返回泛型值,但必须配合 Future 获取结果。
关键点:Future.get() 是阻塞的,调用线程会等直到任务完成或超时;不显式处理超时或中断,容易卡死主线程。
示例:
Callable<Integer> task = () -> {
Thread.sleep(1000);
return 42;
};
Future<Integer> future = Executors.newSingleThreadExecutor().submit(task);
System.out.println(future.get()); // 阻塞等待
-
Future本身不提供异步回调,JDK 8+ 更推荐CompletableFuture - 线程池提交
Callable后,记得shutdown(),否则 JVM 可能不退出 - 异常不会在
submit()时抛出,而是在get()时包装成ExecutionException
线程创建不是终点,生命周期管理常被忽略
很多人只关注“怎么启”,却忘了“怎么停”和“怎么查”。Java 线程没有安全的强制终止接口,stop() 已废弃;靠 interrupt() + 主动检查才是正路。
典型疏漏:
- 未响应中断:在
run()中没检查Thread.interrupted()或捕获InterruptedException - 资源泄漏:线程持有数据库连接、文件句柄,但没在
finally或 try-with-resources 中释放 - 线程名缺失:不设
setName(),出问题时日志里全是Thread-0、Thread-1,排查困难 - 无监控:不记录线程创建位置(比如用
Thread.currentThread().getStackTrace()打点),线上线程数飙升时无法定位源头










