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

6.Java多线程详解:Thread类、线程属性与start()方法深度解析

目录

Thread 类其他的属性和方法~~

Thread 构造方法概览:

name 属性说明:

Thread 的几个常见属性

前台线程 vs 后台线程

启动一个线程 - start()

中断一个线程

启动一个线程 - start()

变量捕获与 lambda / 匿名内部类

Thread 提供更靠谱的方案实现上述的效果

日常开发中 catch 中的逻辑一般不会这么写~~


Thread 类其他的属性和方法~~

Thread 构造方法概览:

  • Thread()

    创建线程对象。

  • Thread(Runnable target)

    使用 Runnable 对象创建线程对象。

  • Thread(String name)

    创建线程对象,并命名。

  • Thread(Runnable target, String name)

    使用 Runnable 对象创建线程对象,并命名。

  • 【了解】Thread(ThreadGroup group, Runnable target)

    使用 Runnable 对象创建线程对象,并分组。

    说明:线程组可以方便批量管理,分组的组别为线程组。多用在底层代码开发中。

批注name给线程起名字——不影响线程的执行,方便调试~~


name 属性说明:

默认线程名字为Thread-数字(如Thread-0,Thread-1等)。

代码示例

Thread t3 = new Thread(() -> { while (true) { System.out.println("t3"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, "t3");

Thread 的几个常见属性

属性

获取方法

说明

ID

getId()

ID 是线程的唯一标识,不同线程不会重复

名称

getName()

全是给程序员调试工具用

状态

getState()

状态表示线程所处的某个情况,下面我们会进一步说明

优先级

getPriority()

优先级高的线程理论上更容易被调度到

是否后台线程

isDaemon()

关于后台线程,再说后一点。JVM 会在所有程序的所有后台线程结束后,才会结束运行。是否后台,但简单的理解,为 true 方法是否运行起来

是否存活

isAlive()

线程的中断问题,下面我们进一步说明

补充说明

  • 线程组(ThreadGroup)现在很少涉及到,后续介绍“线程池”生态位上替代了线程组~~

  • main线程包括代码中手动创建的线程,默认都是前台线程~~

  • 返回 0 表示进程执行成功,非 0 值表示失败,使用不同的值表示不同的错误原因~~

  • 学习 C 语言的时候,hello world中的int main() { return 0; },进程结束返回码~~


前台线程 vs 后台线程

  • 前台线程:会阻止整个进程结束。

    举例:李局长要是撤了,宴席就会结束了(主角退场)。

  • 后台线程:不会阻止整个进程结束。

    举例:如果我吃饱了,我说我要撤了,是否会使宴席结束呢?——后台线程~~

一个进程中的前台线程,不止有一个~~

得是所有的前台线程都结束了,进程才结束~~

后台线程:也叫做“守护线程”

“默默”背后默默的守护~~

“等你下课” 🎵


启动一个线程 - start()

start操作本质上会调用操作系统提供的 API,在操作系统的内部(内核)创建出一个线程出来了。

private native void start0();
  • Java 的代码 =>.class,再经过 JVM 解释执行的~~

  • 带有native字样的方法,就是在 JVM 内部通过 C++ 实现的方法。

  • 调用操作系统的原生 API 创建线程,根据当前的操作系统做区分~~

  • 内部是一系列的#if#ifdef#else if#elseC/C++来说)

  • 操作系统内部,通过PCB​ 来描述,通过链表组织~~

  • 对于 Linux 来说(Linux 开源,Windows 闭源)

    “被调度起来后执行的逻辑,就是 run 里面设定的刚刚逻辑~~”

图示说明

  • 操作系统拿着 PCB 结构体来进行调度执行~~

  • pid:每个 PCB 对应一个线程,在 PCB 上有一个特质的id属性,这个id是相同同的,也就是一个进程~~

start 方法本身,执行速度非常快~~

start针对一个 thread 对象,只能调用一次~~

Java 设定了,要让一个 thread 对象和一个操作系统的线程一一对应~~


中断一个线程

英文术语:Interrupt—— 我个人更喜欢称为“终止”

对于 Java 来说,一个线程终止,就是这个线程的入口方法执行完毕~~

Java 并不提供“强制终止”(所有的让线程终止的做法,都需要等待着“让入口方法结束”)

有些危险

  • A 线程调用方法,终止 B 线程。

  • 调用 A 的终止方法时,无法确定 B 线程当前执行到哪个环节了~~

  • 做某个事情,做了一半,就被强制终止了~~


启动一个线程 - start()

之前我们已经看到了如何通过重写run方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。

  • 重写run方法是提供给线程要做的事情的命令清单。

  • 线程对象可以认为是把 李四、王五叫过来了。

  • 而调用start()方法,就是喊一声:“劳动啦!”,线程才真正独立去执行了。

流程图说明

  1. 学员 A(新线程):执行逻辑、响应主线程的通知、A 线程结束。

  2. 老师(主线程):开始新线程、去查看任务结果、等待 A 线程结束、汇总到评分系统。

调用 start 方法,才真的在操作系统的层面创建出一个线程。


变量捕获与 lambda / 匿名内部类

写作局部变量,此时无法编译通过~~

变量捕获:lambda / 匿名内部类

捕获的变量,必须是final/ 事实 final

错误示例

boolean running = true; Thread t = new Thread(() -> { while (running) { // 编译错误:Variable used in lambda expression should be final or effectively final System.out.println("hello thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } System.out.println("t 线程退出"); }); t.start();

写作成员变量,情况就不一样~~

触发的做法不再是“变量捕获”,而是“内部变量向外部变成了类”。

正确示例(使用成员变量)

private static boolean running = true; public static void main(String[] args) { Thread t = new Thread(() -> { while (running) { System.out.println("hello thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } System.out.println("t 线程退出"); }); t.start(); // 主线程中,让用户选择是否让 t 线程终止 Scanner sc = new Scanner(System.in); System.out.println("请输入整数,0 表示不让 t 线程终止:"); int n = sc.nextInt(); if (n == 0) { running = false; } }

说明

  • lambda 本质上是基于函数式接口的匿名内部类。

C++ 的考虑:程序自行负责保证变量的生命周期匹配~~

Java 的考虑:变量的生命周期由 JVM 托管,更加安全~~

一旦修改了局部变量的生命周期可能出现不一致,代码更乱。

为了避免混乱,Java 直接禁止修改~~


Thread 提供更靠谱的方案实现上述的效果

获取当前线程的引用

这个 lambda 在哪个线程中执行的,得到的引用就是哪个线程Thread引用~~

while (!Thread.currentThread().isInterrupted()) { System.out.println("hello thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } System.out.println("t 线程退出");

示例完整代码

package thread; import java.util.Scanner; public class Demo9 { public static void main(String[] args) { Thread t = new Thread(() -> { Thread cur = Thread.currentThread(); while (!cur.isInterrupted()) { System.out.println("hello thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); t.start(); Scanner scanner = new Scanner(System.in); System.out.println("请输入整数表示让线程 t 结束:"); int n = scanner.nextInt(); if (n == 0) { // 这个方法不光可以设置标志位,还能唤醒 sleep 等导致线程阻塞的方法 // 会使 sleep 漏出异常,InterruptedException t.interrupt(); } } }

执行逻辑说明

  • 执行这个代码的时候,一定是先针对Thread t中的参数,先进行求值。

  • 在执行Thread的构造方法。

  • 在把Thread构造方法的结果,赋值给t(定义 + 符合)

图示说明

  • Thread cur = Thread.currentThread();

    this表示当前对象

    currentThread表示当前线程

Thread 对象内部,封装了一个 boolean 变量

效果

  • 这个和手动修改标志位类似。

  • 还额外做了其他操作,把sleep这样的方法唤醒。

异常信息(将来常用)

Exception in thread "t 线程" java.lang.RuntimeException: java.lang.InterruptedException: sleep interrupted at thread.Demo9.lambda$main$0(Demo9.java:14) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.InterruptedException: sleep interrupted at java.base/java.lang.Thread.sleep(Native Method) at thread.Demo9.lambda$main$0(Demo9.java:11) ... 1 more

Process finished with exit code 0


日常开发中 catch 中的逻辑一般不会这么写~~

IDEA 生成的爆栈代码~~

try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); }

实现开发中 catch 根据阻塞的不同,采取不同的动作

  1. 尝试重试~~

  2. 记录错误 / 日志~~(记到日志文件,写入到日志服务器中)

  3. 触发报警 / 短信~~(钉钉群、企业微信、邮件...)

http://www.jsqmd.com/news/897050/

相关文章:

  • 广东东莞专业的自动包装机圆角冲刀厂家推荐 - 变量人生001
  • AI品牌命名决策框架(2024全球TOP 10生成式AI产品命名深度复盘)
  • 终极指南:如何让微信同时登录手机和平板?WeChatPad免费解决方案
  • 5分钟快速上手ESP32开发:从Arduino到物联网应用实战指南
  • 极化码List-Fast-SSC解码器的高效硬件排序架构设计
  • 使用双氧水(7.5%)制作PCB
  • Keil C51调试器兼容性问题解析与解决方案
  • 【ChatGPT播客内容策划黄金法则】:20年AI内容架构师亲授5步闭环工作流,92%新手72小时内产出爆款选题
  • 用DeepSeek搞定论文降重与降AI!5个实用提示词+降ai率软件,定稿前必看! - 殷念写论文
  • 金价高位|无锡黄金回收,拒绝鬼秤,实价回收 - 奢侈品回收测评
  • 图片水印怎么去除?这款去水印神器一定要码住!
  • 终极解密指南:3分钟免费解锁网易云NCM音乐,实现跨平台自由播放
  • 嵌入式CPU实时大气湍流校正:免配准NCC融合方案详解
  • 告别手动复制粘贴!Open-Multiple-URLs 让批量打开链接变得如此优雅
  • 测试ADS1244,增加参考电压以及输入信号滤波
  • 告别数字垃圾:AntiDupl.NET开源工具帮你智能清理重复图片
  • 文献阅读 260526-Sustained deoxygenation in global flowing waters under climate warming
  • 大同老旧黄金首饰金条回收靠谱门店甄选攻略:2026年5月六家品牌实测,全程无损检测、免费上门、零隐形扣费,这篇看完不踩坑 - 润富黄金珠宝行
  • 使用范围太有限?试试永辉超市卡回收方法! - 团团收购物卡回收
  • 将Hermes Agent无缝对接至Taotoken的配置要点详解
  • EmulatorJS版本策略深度解析:如何为你的复古游戏体验选择最佳版本
  • 如何免费获取微信视频号和抖音无水印视频?跨平台资源下载神器res-downloader完全指南
  • 3分钟搞定:无需扫描仪,用浏览器把PDF变成专业扫描件
  • 博德之门3脚本扩展器:5分钟掌握终极游戏自定义工具
  • 财富的死亡与重生:从历史货币到数字资产的价值存储逻辑
  • 西宁市2026年5月黄金回收行情解析与六大靠谱渠道盘点,高位金价下变现必看 - 润富黄金珠宝行
  • Dynadot管理域名数量已经突破1000万!
  • 国内热门CRM软件汇总:品牌实力与落地效果盘点 - Joyky
  • 51单片机中断与定时器核心:IE、TCON、TMOD寄存器配置全解析
  • 现在买iPhone,亏大了