继承thread最直接但不灵活,因java单继承限制且无法复用线程;实现runnable是主流推荐方式,解耦任务与线程管理;callable+future适用于需返回值或异常处理的场景;生产环境必须使用线程池(executorservice)统一管理生命周期。

继承 Thread 类是最直接但最不灵活的方式
直接让自定义类 extends Thread,重写 run() 方法,然后调用 start() 启动线程。这种方式简单直观,但 Java 不支持多重继承,一旦类已继承其他父类,就无法再继承 Thread。
常见错误是误调用 run() 而非 start() —— 这会导致方法在当前线程同步执行,根本没产生新线程。
-
start()触发 JVM 创建并调度新线程,之后自动调用run() - 子类中若需访问线程名、优先级等,可直接用
this.getName()、this.setPriority()等 - 无法复用已有线程对象:每个
Thread实例只能start()一次,重复调用抛IllegalThreadStateException
实现 Runnable 接口是推荐的主流做法
Runnable 是函数式接口,只需实现 run() 方法,再将其传给 Thread 构造器或线程池。它解耦了任务逻辑与线程生命周期管理,支持多继承(类可同时 implements Runnable 并继承其他类)。
注意:Runnable 没有返回值,也不能抛受检异常(Exception),这是它和 Callable 的关键区别。
立即学习“Java免费学习笔记(深入)”;
BJXShop网上购物系统是一个高效、稳定、安全的电子商店销售平台,经过近三年市场的考验,在中国网购系统中属领先水平;完善的订单管理、销售统计系统;网站模版可DIY、亦可导入导出;会员、商品种类和价格均实现无限等级;管理员权限可细分;整合了多种在线支付接口;强有力搜索引擎支持... 程序更新:此版本是伴江行官方商业版程序,已经终止销售,现于免费给大家使用。比其以前的免费版功能增加了:1,整合了论坛
- 适合「只执行、不关心结果」的场景,比如日志刷盘、心跳上报
- 可被多个
Thread实例共享,天然支持任务复用(但要注意共享状态的线程安全) - 传入线程池时,实际执行的是
ThreadPoolExecutor.execute(Runnable),不是submit()
使用 Callable + Future 获取带返回值的异步结果
当需要线程执行后返回结果或捕获异常时,必须用 Callable 替代 Runnable。它定义了 call() 方法,允许返回泛型值、抛出任意异常。
但 Callable 不能直接交给 Thread,必须配合 FutureTask(包装成 Runnable)或更常用的是线程池的 submit() 方法。
-
Future.get()是阻塞调用,超时未完成会抛TimeoutException,务必处理中断(InterruptedException) - 线程池
submit(Callable)返回Future,底层实际创建的是FutureTask对象 - 如果任务本身耗时长且无需结果,强行用
Callable反而增加封装开销,不如用Runnable
用线程池(ExecutorService)管理线程生命周期才是生产环境标配
手动 new Thread().start() 在高并发下极易导致 OOM(线程数爆炸)或上下文切换开销过大。所有真实项目都应使用 ExecutorService,例如 Executors.newFixedThreadPool(4) 或更稳妥的 ThreadPoolExecutor 自定义构造。
四种“实现方式”里,只有线程池是真正面向工程落地的方案;其余三种本质都是定义任务(Runnable/Callable),而线程池负责执行、复用、拒绝、监控。
-
execute(Runnable)用于无返回值任务;submit()支持Runnable和Callable,返回Future - 别用
Executors工厂方法创建无界队列的线程池(如newCachedThreadPool),容易堆内存溢出 - 关闭线程池必须调用
shutdown()+awaitTermination(),否则 JVM 可能不退出
真正复杂的点不在“怎么写个线程”,而在于任务划分粒度、共享状态的可见性与原子性、线程池参数与业务吞吐的匹配——这些不会因为选了 Runnable 还是 Callable 就自动解决。









