Java线程是如何创建的_常见创建方式对比总结

发布时间 - 2026-01-27 00:00:00    点击率:
推荐使用 ExecutorService + Callable 或 CompletableFuture:前者适用于需返回值和异常处理的场景,后者适合异步编排;手写 Thread 子类仅限教学或极简场景,实际项目中应重视线程池配置细节。

直接继承 Thread 类:简单但不推荐

这是最直观的创建方式,定义一个类继承 Thread,重写 run() 方法,然后调用 start() 启动。

问题在于 Java 不支持多重继承,一旦你的业务类已经继承了其他父类,这条路就走不通;而且线程逻辑和业务逻辑耦合过紧,不利于复用和测试。

  • start() 才真正启动新线程;直接调用 run() 只是普通方法执行,不会开启线程
  • 每个任务都需要新建一个子类,无法复用已有线程资源
  • 无法返回执行结果,也不方便捕获异常(异常会直接抛到 Thread 的未捕获处理器)

实现 Runnable 接口:更灵活的基础方案

把任务逻辑封装进 Runnable 实现类,再传给 Thread 构造器。这是解耦的第一步,也是最常用的起点。

它规避了继承限制,也更适合面向接口编程。但仍有局限:不能返回值、不能抛受检异常、无法获取执行状态。

Thread t = new Thread(new Runnable() {
    public void run() {
        System.out.println("Hello from Runnable");
    }
});
t.start();
  • 适合「只做一件事、不关心结果」的场景,比如日志异步刷盘、心跳上报
  • 可配合线程池使用:ExecutorService.submit(Runnable) 会忽略返回值
  • 若需返回值,必须自己加共享变量 + 同步控制,容易出错

实现 Callable + Future:需要结果时的标准解法

当任务需要返回值或可能抛出异常时,CallableRunnable 的增强替代。它用 call() 方法代替 run(),支持泛型返回值和受检异常。

Callable 不能直接交给 Thread,必须通过 ExecutorService 提交,返回 Future 对象来取结果或判断状态。

ExecutorService executor = Executors.newSingleThreadExecutor();
Future future = executor.submit(() -> {
    Thread.sleep(1000);
    return "Done";
});
String result = future.get(); // 阻塞等待
executor.shutdown();
  • future.get() 默认阻塞,超时版本 get(long, TimeUnit) 更安全
  • isDone()isCancelled() 可用于轮询状态,但轮询本身有性能开销
  • 线程池关闭前务必调用 shutdown()shutdownNow(),否则 JVM 不会退出

使用 ForkJoinPool / CompletableFuture:复杂并发任务的现代选择

对于可拆分的计算密集型任务(如归并排序、树遍历),ForkJoinPool 提供工作窃取机制,比普通线程池更高效;而 CompletableFuture 则让异步编排变得声明式、可组合。

它们不是“创建线程”的底层方式,而是更高层的抽象——你不再手动管理 Thread 实例,而是描述任务依赖与执行策略。

  • CompletableFuture.supplyAsync(...) 默认使用 ForkJoinPool.commonPool(),注意其线程数固定(通常为 CPU 核数 -1),IO 密集型任务应显式传入自定义线程池
  • ForkJoinPool 中的子任务不要调用 join() 外部 ForkJoinTask,否则可能引发死锁
  • 过度使用 CompletableFuture.thenApplyAsync 而不指定线程池,容易耗尽 commonPool,拖慢整个应用
实际项目里,90% 的异步需求用 ExecutorService + CallableCompletableFuture 就够了;手写 Thread 子类几乎只出现在教学或极简嵌入式场景中。真正容易被忽略的是线程池配置

——大小、队列类型、拒绝策略,这些细节往往比“怎么创建”更能决定系统稳定性。


# java  # 处理器  # app  # jvm  # 封装  # 父类  # 子类  # 归并排序  # 继承  # 接口  # 多重继承  # 泛型  # 线程  # Thread  # 并发  # 对象  # 异步  # 返回值  # 这是  # 死锁  # 装进  # 复用  # 的是  # 也不  # 已有  # 出现在 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 如何自定义建站之星网站的导航菜单样式?  七夕网站制作视频,七夕大促活动怎么报名?  详解CentOS6.5 安装 MySQL5.1.71的方法  详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)  Laravel如何使用Eloquent ORM进行数据库操作?(CRUD示例)  如何为不同团队 ID 动态生成多个“认领值班”按钮  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  Java Adapter 适配器模式(类适配器,对象适配器)优缺点对比  北京网站制作公司哪家好一点,北京租房网站有哪些?  高防服务器租用如何选择配置与防御等级?  Laravel怎么配置S3云存储驱动_Laravel集成阿里云OSS或AWS S3存储桶【教程】  在centOS 7安装mysql 5.7的详细教程  Laravel如何监控和管理失败的队列任务_Laravel失败任务处理与监控  简单实现Android验证码  Laravel观察者模式如何使用_Laravel Model Observer配置  如何在阿里云完成域名注册与建站?  Laravel如何使用withoutEvents方法临时禁用模型事件  Laravel如何实现邮箱地址验证功能_Laravel邮件验证流程与配置  Laravel如何实现图片防盗链功能_Laravel中间件验证Referer来源请求【方案】  Android仿QQ列表左滑删除操作  如何在阿里云ECS服务器部署织梦CMS网站?  深入理解Android中的xmlns:tools属性  如何制作新型网站程序文件,新型止水鱼鳞网要拆除吗?  WEB开发之注册页面验证码倒计时代码的实现  Laravel如何使用Vite进行前端资源打包?(配置示例)  Laravel Seeder怎么填充数据_Laravel数据库填充器的使用方法与技巧  Laravel怎么多语言本地化设置_Laravel语言包翻译与Locale动态切换【手册】  Windows10如何更改计算机工作组_Win10系统属性修改Workgroup  浅述节点的创建及常见功能的实现  Python面向对象测试方法_mock解析【教程】  Win11怎么查看显卡温度 Win11任务管理器查看GPU温度【技巧】  浅谈javascript alert和confirm的美化  Laravel如何使用Service Container和依赖注入?(代码示例)  微信小程序 HTTPS报错整理常见问题及解决方案  如何用美橙互联一键搭建多站合一网站?  Laravel怎么在Blade中安全地输出原始HTML内容  个人网站制作流程图片大全,个人网站如何注销?  Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】  如何快速登录WAP自助建站平台?  Laravel如何实现API速率限制?(Rate Limiting教程)  Laravel如何实现多语言支持_Laravel本地化与国际化(i18n)配置教程  Laravel的契約(Contracts)是什么_深入理解Laravel Contracts与依赖倒置  如何使用 Go 正则表达式精准提取括号内首个纯字母标识符(忽略数字与嵌套)  Laravel Blade组件怎么用_Laravel可复用视图组件的创建与使用  油猴 教程,油猴搜脚本为什么会网页无法显示?  Laravel怎么实现验证码功能_Laravel集成验证码库防止机器人注册  Laravel路由Route怎么设置_Laravel基础路由定义与参数传递规则【详解】  Android okhttputils现在进度显示实例代码