当前位置: 首页 > java >正文

Java 中实现线程的创建和启动

在 Java 中,实现线程的创建启动是两个不同但紧密相关的概念。理解为什么要启动线程(调用 start() 方法)而非直接调用 run() 方法,是掌握多线程编程的关键。以下是详细解释:


1. 线程的生命周期

Java 线程有明确的生命周期状态:

start()
获得CPU资源
run()结束
等待I/O/锁
资源可用
New(新建)
New
Runnable(可运行)
Runnable
Running(运行)
Running
Terminated(终止)
Blocked(阻塞)
Blocked
  • 新建状态(New):创建 Thread 对象后(如 new MyThread()),线程尚未启动
  • 可运行状态(Runnable):调用 start() 后,线程进入就绪队列
  • 运行状态(Running):线程获得 CPU 时间片,执行 run() 方法
  • 终止状态(Terminated)run() 执行完毕

关键点:只有调用 start() 才能使线程从 New 进入 Runnable 状态!


2. start() vs run() 的本质区别

方法工作方式线程数量执行位置
start()JVM 创建新线程并执行 run()新线程独立调用栈
run()直接调用普通方法当前线程当前线程调用栈

错误示例

Thread thread = new Thread(() -> System.out.println("执行中"));
thread.run();  // 错误!在主线程同步执行

正确示例

thread.start(); // 正确!启动新线程异步执行

3. 为什么必须通过 start() 启动线程?

(1) 资源分配

调用 start() 时,JVM 会:

  1. 为线程分配独立调用栈(Stack)
  2. 注册线程到系统调度器
  3. 触发操作系统级别的线程创建
(2) 异步执行
  • start() 使任务在后台异步执行,不阻塞当前线程
  • 直接调用 run()同步执行,阻塞当前线程
(3) 线程调度控制

只有通过 start() 启动的线程才能被:

  • 线程调度器管理(优先级、时间片分配)
  • 正确响应中断(interrupt()
  • 加入线程池统一管理
(4) 状态合规性

多次调用 start() 会抛出 IllegalThreadStateException,而 run() 可重复调用。这保证了线程状态机的正确性。


4. 底层机制

当调用 start() 时:

public synchronized void start() {if (threadStatus != 0)  // 检查状态是否为NEWthrow new IllegalThreadStateException();group.add(this);  // 加入线程组boolean started = false;try {start0();  // 关键!调用本地方法started = true;} finally {// ...错误处理}
}private native void start0();  // JVM实现的本地方法
  • start0()native 方法,由 JVM 通过操作系统 API 创建真实线程
  • 新线程创建后自动执行 run() 方法

5. 实际应用场景

假设需要同时下载3个文件:

// 错误方式(顺序下载)
new DownloadTask("url1").run(); // 阻塞主线程
new DownloadTask("url2").run(); // 等待前一个完成
new DownloadTask("url3").run();// 正确方式(并行下载)
new Thread(new DownloadTask("url1")).start(); // 异步
new Thread(new DownloadTask("url2")).start(); // 异步
new Thread(new DownloadTask("url3")).start(); // 异步

结论

操作结果是否启动线程
new Thread()创建线程对象(NEW状态)
start()启动线程(进入RUNNABLE状态)
run()普通方法调用

必须调用 start() 才能

  1. 创建真正的操作系统线程
  2. 实现任务异步执行
  3. 符合线程生命周期规范
  4. 利用多核CPU实现并行计算

直接调用 run() 只是普通方法调用,完全违背了多线程的设计目的!

http://www.xdnf.cn/news/12053.html

相关文章:

  • [ACM MM 2024]Lite-Mind:Towards Efficient and Robust Brain Representation
  • MySQL对数据库用户的操作
  • VS Code开发项目,配置ESlint自动修复脚本
  • 高防CDN有用吗?它的防护效果怎么样?
  • 1. 数据库基础
  • 卫星的“太空陀螺”:反作用轮如何精准控制姿态?
  • 蓝桥云课ROS一键配置teb教程更新-250604
  • 嵌入式就业难不难?
  • 【趣味Html】第11课:动态闪烁发光粒子五角星
  • 力扣刷题Day 70:在排序数组中查找元素的第一个和最后一个位置(34)
  • Visual Studio 2022 在 Windows 11 添加资源时崩溃问题分析与解决方案
  • [Linux] Linux GPIO应用编程深度解析与实践指南(代码示例)
  • JAVA实战开源项目:医院药品管理系统 (Vue+SpringBoot) 附源码
  • 数组1 day7
  • zabbix 6 监控 docker 容器
  • Linux 库文件的查看和管理
  • 解决 Java 项目中 “zip END header not found“ 错误
  • 【el-progress】element UI 进度条组件
  • 易基因:贵州省医刘代顺团队MeRIP-seq揭示m6A修饰在病毒感染中的免疫调控作用 | 项目文章
  • AI Agent 能否理解人类的行为和决策?
  • Java - 数组
  • 【docker】Windows安装docker
  • [Java 基础]抽象类和接口
  • 马尔可夫链(Markov Chain)和马尔可夫决策过程(Markov Decision Process, MDP)
  • ST语言控制电机往返运动
  • Flink进阶之路:解锁大数据处理新境界
  • 背景扩充:糖苷键的类型与表示方法 +python实现对糖分子名称的读取
  • JAVA容器
  • 从零开始:用Tkinter打造你的第一个Python桌面应用
  • 自驾总结_Routing