Java零基础之多线程篇:线程生命周期
哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云;欢迎大家常来逛逛
今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。
我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!
前言
在并发编程中,多线程是一种非常重要的技术手段,理论知识及线程创建我已经在上一章节讲过了,本章我们就不再赘述。我们都知道Java作为一种广泛应用的开发语言,提供了丰富的多线程编程支持。了解并掌握Java多线程的生命周期对于编写高效且可靠的多线程程序至关重要。所以在本文中,我将介绍Java多线程的生命周期,包括线程状态的转换和对应的方法调用,作为新一期的内容进行讲解,这也是为了帮助大家学习上能够循序渐进。
摘要
本文我的讲解思路是:首先通过简介介绍Java多线程的基本概念和特性,然后深入探讨线程的生命周期,包括线程的状态转换和相关的方法调用。此外,本文还将通过源代码解析、应用场景案例和优缺点分析等方式,帮助读者更好地理解和应用线程的生命周期。
简介
多线程是指在一个程序中同时进行多个线程的执行,每个线程具有独立的执行路径。在Java中,每个线程都有自己的生命周期,包括新建、就绪、运行、阻塞和终止等不同状态。线程状态的转换由Java虚拟机自动控制,但是开发人员可以通过方法调用来干预线程的状态。
源代码解析
在Java中,创建一个线程最常见的方式是继承Thread类或实现Runnable接口。以下是一个简单的示例代码:这里我们主要是以回顾+温习为主,毕竟上一章节已经学完的内容。
/*** @Author ms* @Date 2024-04-12 18:27*/
public class MyRunnable implements Runnable {public void run() {// 线程执行的代码System.out.println("线程执行啦!");}
}public class ThreadDemo {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);thread.start();System.out.println("主线程执行啦!");}
}
在上述代码中,MyThread类继承了Thread类,并重写了run方法。在ThreadDemo 类中,创建了一个MyThread实例,并调用start方法启动线程。
执行结果肯定如下所示:

还不够熟练地同学,这里也可以再多敲敲试一下。
应用场景案例
这里我们来谈谈,多线程可以应用于的各种场景,包括并发访问共享资源、提高程序性能、实现异步任务等。以下是几个常见的应用场景案例:
- 并发访问共享资源:多个线程同时访问同一个共享资源时,会出现竞态条件。使用多线程可以解决并发访问共享资源的问题,提高程序的执行效率。
- 提高程序性能:将耗时的任务拆分成多个子任务,用多线程同时执行,可以显著提高程序的运行速度。
- 实现异步任务:多线程可以在后台执行耗时的操作,让程序能够同时响应用户的输入和其他事件。
优缺点分析
多线程编程有很多优点,同时也存在一些缺点,毕竟任何事物都要辩证看待。以下是对多线程编程的优缺点分析:
优点:
- 提高程序的执行效率,充分利用多核处理器的计算能力。
- 改善用户体验,使程序能够同时响应用户的输入和其他事件。
- 实现复杂的并发控制,提高程序的可扩展性和可维护性。
缺点:
- 多线程编程更加复杂,需要考虑线程安全、竞态条件等问题。
- 线程间的通信和同步开销较大,可能引入死锁和性能损失等问题。
- 调试和问题排查更加困难,因为多线程程序的执行顺序不确定。
类代码方法介绍
在Java中,线程类常用的方法有以下几种:
- start():启动线程,并调用线程的run方法。
- sleep():使线程进入休眠状态,暂停执行一段时间。
- join():等待线程执行完毕,再继续执行当前线程。
- interrupt():中断线程的执行。
熟悉上述方法后,我们就要来实战演示了。
Java代码测试用例
以下是一个简单的Java多线程测试用例,用于计算从1到10的累加和,代码演示如下,仅供参考:
package com.example.javase.ms.threadDemo.day2;/*** @Author ms* @Date 2024-04-12 19:09*/
public class MyThread extends Thread {private static int sum = 0;public void run() {for (int i = 1; i <= 10; i++) {sum += i;}}public static void main(String[] args) throws InterruptedException {MyThread thread1 = new MyThread();MyThread thread2 = new MyThread();thread1.start();thread2.start();thread1.join();thread2.join();System.out.println("Sum is: " + sum);}
}
在上述代码中,MyThread类继承了Thread类,并重写了run方法。在主线程中,创建了两个MyThread实例,并分别启动两个线程。最后,使用join方法等待两个线程执行完毕,并打印累加和。
测试结果展示:
当程序运行时,它将创建两个线程,每个线程都会独立地计算从1到10的和。由于线程的执行是由操作系统的线程调度器控制的,所以两个线程完成计算的顺序是不确定的。但是,由于join()方法的使用,我们可以确保在主线程打印sum的值之前,两个线程都已经完成了它们的计算。结果展示如下:

其实上述代码,从执行结果上来看,不知道大家有没有发现问题!可以评论区交流下,虽然我下文也会给出对应的代码优化。
测试代码解析:
根据如上代码作出解析,以便于同学们更好的理解,分析如下:
如上测试用例展示了一个简单的多线程示例,其中创建了两个线程,每个线程都执行一个for循环来计算从1到10的整数和。这个示例使用了Thread类来创建和管理线程。
-
MyThread类继承了Thread类,并重写了run()方法。在run()方法中,通过一个循环计算从1到10的整数和,并将结果累加到静态变量sum中。 -
在
main方法中,创建了两个MyThread对象:thread1和thread2,并且分别启动了这两个线程。 -
thread1.join();和thread2.join();这两行代码使得主线程等待thread1和thread2完成执行。join()方法确保了在主线程继续执行之前,当前线程(在这个例子中是thread1和thread2)已经终止。 -
最后,一旦两个线程都完成了它们的计算,主线程将打印出静态变量
sum的值。
注意事项
- 由于
sum是一个静态变量,它在所有MyThread实例之间共享。这意味着两个线程都会访问和修改同一个sum变量,这可能导致线程安全问题,如竞态条件。这里就是我上述所提到的问题。 - 在这个特定的例子中,由于每次只有一个线程在执行
run()方法,所以不会出现竞态条件。但是,如果sum的更新是在多个线程中并发进行的,那么就需要使用同步机制来确保线程安全。
改进建议
那么如何避免潜在的线程安全问题呢?其实很简单,这里我们可以使用synchronized关键字来同步对sum的访问。优化代码如下:
/*** @Author ms* @Date 2024-04-12 19:14*/
public class MyThread_update extends Thread {private static final Object lock = new Object();private static int sum = 0;public void run() {for (int i = 1; i <= 10; i++) {synchronized (lock) {sum += i;}}}public static void main(String[] args) throws InterruptedException {MyThread_update thread1 = new MyThread_update();MyThread_update thread2 = new MyThread_update();thread1.start();thread2.start();thread1.join();thread2.join();System.out.println("Sum is: " + sum);}
}
在这个改进的版本中,我们使用了一个对象lock作为同步锁。在每次更新sum变量时,我们都会获取这个锁,这样可以确保在同一时间只有一个线程能够执行更新操作。这有助于防止多个线程同时写入sum变量,从而避免竞态条件。
然后,我们再来执行测试一下,结果展示如下:

全文小结
本文介绍了Java多线程的生命周期,包括线程状态的转换和对应的方法调用。通过源代码解析、应用场景案例和优缺点分析等方式,帮助读者更好地理解和应用线程的生命周期。同时,通过Java代码测试用例演示了多线程的具体应用。
总结
了解和掌握Java多线程的生命周期对于编写高效且可靠的多线程程序至关重要。本文通过介绍线程的状态转换、方法调用和具体应用场景,为读者提供了丰富的知识和实践经验。通过合理地应用多线程技术,开发人员可以提高程序的执行效率,改善用户体验,并解决复杂的并发控制问题。
… …
文末
好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。
… …
学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!
wished for you successed !!!
⭐️若喜欢我,就请关注我叭。
⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。
相关文章:
Java零基础之多线程篇:线程生命周期
哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一…...
技术差异,应用场景;虚拟机可以当作云服务器吗
虚拟机和云服务器是现在市面上常见的两种计算资源提供方式,很多人把这两者看成可以相互转换或者替代的物品,实则不然,这两种资源提供方式有许多相似之处,但是也有不少区别,一篇文章教你识别两者的技术差异,…...
Qt Quick 教程(一)
文章目录 1.Qt Quick2.QML3.Day01 案例main.qml退出按钮,基于上面代码添加 4.使用Qt Design StudioQt Design Studio简介Qt Design Studio工具使用版本信息 1.Qt Quick Qt Quick 是一种现代的用户界面技术,将声明性用户界面设计和命令性编程逻辑分开。 …...
react钩子函数用法(useCallback、useMemo)
useMemo import { useMemo } from react; function MyComponent({ a, b }) { const memoizedValue useMemo(() > { // 进行一些昂贵的计算 return a b; }, [a, b]); // 当 a 或 b 发生变化时,memoizedValue 将被重新计算 return <div>{memoizedVa…...
linux配置Vnc Server给Windows连接
1. linux 安装必要vnc server和桌面组件 sudo apt -y install tightvncserversudo apt install xfce4 xfce4-goodies2. linux 配置vncserver密码 #bash vncserver参考: https://cn.linux-console.net/?p21846#google_vignette 3. 将启动桌面命令写入.vnc/xstartup # .vnc/x…...
Android中的KeyEvent详解
介绍 在Android中,KeyEvent 是用来表示按键事件的类,可根据对应的事件来处理按键输入,具体包含了关于按键事件的信息,例如按键的代码、动作(按下或释放)以及事件的时间戳,KeyEvent 对象通常在用…...
移植案例与原理 - HDF驱动框架-驱动配置(2)
1.2.7 节点复制 节点复制可以实现在节点定义时从另一个节点先复制内容,用于定义内容相似的节点。语法如下,表示在定义"node"节点时将另一个节点"source_node"的属性复制过来。 node : source_node示例如下,编译后bar节点…...
年终奖发放没几天,提离职领导指责我不厚道,我该怎么办?
“年终奖都发了,你还跳槽?太不厚道了吧!” “拿完年终奖就走人,这不是典型的‘骑驴找马’吗?” 每到岁末年初,关于“拿到年终奖后是否应该立即辞职”的话题总会引发热议。支持者认为,这是个人…...
多处理系统结构
目录 统一内存访问(UMA)多处理器系统结构 优点 缺点 应用场景 UMA 结构的架构示例 解决方案和改进 非统一内存访问(NUMA)多处理系统结构 概述 NUMA的优点 NUMA的缺点 NUMA系统的工作原理 NUMA优化策略 结论 现代计算…...
创建进程的常用方式
自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在Python中有多个模块可以创建进程,比较常用的有os.fork()函数、multiprocessing模块和Pool进程池。由于os.fork()函数只适用于Unix/Linu…...
李宏毅2023机器学习作业HW06解析和代码分享
ML2023Spring - HW6 相关信息: 课程主页 课程视频 Sample code HW06 视频 HW06 PDF 个人完整代码分享: GitHub | Gitee | GitCode P.S. HW06 是在 Judgeboi 上提交的,出于学习目的这里会自定义两个度量的函数,不用深究,遵循 Sugge…...
专业技能篇--算法
文章目录 前言经典算法思想总结一、贪心算法二、动态规划三、回溯算法四、分治算法 前言 这篇简单理解一些常见的算法。如果面试的时候问到相关的算法,能够应付一二。 经典算法思想总结 一、贪心算法 思想:贪心算法是一种在每一步选择中都采取在当前状…...
Vue中CSS动态样式绑定
Vue中CSS动态样式绑定与注意事项_vue css动态绑定-CSDN博客 在 Vue 中,你不能直接在 CSS 中直接绑定 data 中的数据,因为 CSS 不是响应式的。但是,有几种方法可以实现根据 Vue 实例中的数据来动态地改变样式: 内联样式绑定&…...
【漏洞复现】契约锁电子签章平台 add 远程命令执行漏洞(XVE-2023-23720)
0x01 产品简介 契约锁电子签章平台是上海亘岩网络科技有限公司推出的一套数字签章解决方案。契约锁为中大型组织提供“数字身份、电子签章、印章管控以及数据存证服务”于一体的数字可信基础解决方案,可无缝集成各类系统,让其具有电子化签署的能力,实现组织全程数字化办公。通…...
计算机专业是否仍是“万金油”?
身份角度一:一名曾经的计算机专业学生 随着高考的结束,我站在了人生的分岔路口,面临着大学专业的选择。在众多的选择中,计算机专业一直是我深思熟虑后的一个重要选项。然而,我并不清楚自己是否真的适合这个专业&…...
Spring 启动顺序
在 Spring 框架中,应用启动过程涉及多个步骤和组件的初始化。理解 Spring 启动顺序不仅有助于优化应用性能,还能帮助开发人员排查启动过程中可能出现的问题。本文将详细介绍 Spring 启动过程中的关键步骤和顺序。 1. Spring 启动过程概述 Spring 应用的…...
2024.06.19 刷题日记
41. 缺失的第一个正数 这个题目的通过率很低,是一道难题,类似于脑筋急转弯,确实不好想。实际上,对于一个长度为 N 的数组,其中没有出现的最小正整数只能在 [1,N1] 中。 这个结论并不好想,举个例子&#x…...
linux系统中,pwd获取当前路径,dirname获取上一层路径;不使用 ../获取上一层路径
在实际项目中,我们通常可以使用 pwd 来获取当前路径,但是如果需要获取上一层路径,有不想使用 …/ 的方式,可以尝试使用 dirname指令 测试shell脚本 #!/bin/bash# 获取当前路径 CURRENT_PATH$PWD echo "CURRENT_PATH$CURREN…...
DeepSpeed Monitoring Comm. Logging
Monitoring 支持多种后端:Tensorboard、WandB、Comet、CSV文件; TensorBoard例子: 自动监控:DeepSpeed自动把重要metric记录下来。只需在配置文件里enable相应的看板后端即可: {"tensorboard": {"enabl…...
关于INCA的几个实用功能
01--VUI窗口设计 这个可以按照自己的想法设计INCA观测或标定窗口 首先进入到INCA的环境内,点击实验→加载VUI窗口 选择空的窗口 打开后如下所示: 点击UI开发模式,如下图 如下: 添加标定量、观测量、示波器 窗口的大小需要在开发…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
