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方法启动线程。

执行结果肯定如下所示:

在这里插入图片描述

  还不够熟练地同学,这里也可以再多敲敲试一下。

应用场景案例

  这里我们来谈谈,多线程可以应用于的各种场景,包括并发访问共享资源、提高程序性能、实现异步任务等。以下是几个常见的应用场景案例:

  1. 并发访问共享资源:多个线程同时访问同一个共享资源时,会出现竞态条件。使用多线程可以解决并发访问共享资源的问题,提高程序的执行效率。
  2. 提高程序性能:将耗时的任务拆分成多个子任务,用多线程同时执行,可以显著提高程序的运行速度。
  3. 实现异步任务:多线程可以在后台执行耗时的操作,让程序能够同时响应用户的输入和其他事件。

优缺点分析

  多线程编程有很多优点,同时也存在一些缺点,毕竟任何事物都要辩证看待。以下是对多线程编程的优缺点分析:

优点:

  • 提高程序的执行效率,充分利用多核处理器的计算能力。
  • 改善用户体验,使程序能够同时响应用户的输入和其他事件。
  • 实现复杂的并发控制,提高程序的可扩展性和可维护性。

缺点:

  • 多线程编程更加复杂,需要考虑线程安全、竞态条件等问题。
  • 线程间的通信和同步开销较大,可能引入死锁和性能损失等问题。
  • 调试和问题排查更加困难,因为多线程程序的执行顺序不确定。

类代码方法介绍

在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类来创建和管理线程。

  1. MyThread类继承了Thread类,并重写了run()方法。在run()方法中,通过一个循环计算从1到10的整数和,并将结果累加到静态变量sum中。

  2. main方法中,创建了两个MyThread对象:thread1thread2,并且分别启动了这两个线程。

  3. thread1.join();thread2.join();这两行代码使得主线程等待thread1thread2完成执行。join()方法确保了在主线程继续执行之前,当前线程(在这个例子中是thread1thread2)已经终止。

  4. 最后,一旦两个线程都完成了它们的计算,主线程将打印出静态变量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 !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/725389.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

.net 6 api 修改URL为小写

我们创建的api项目&#xff0c;url是[Route(“[controller]”)]&#xff0c;类似这样子定义的。我们的controller命名是大写字母开头的&#xff0c;显示在url很明显不是很好看&#xff08;url不区分大小写&#xff09;。转换方式&#xff1a; var builder WebApplication.Crea…

【JS重点18】原型链(面试重点)

一&#xff1a;原型链底层原理 以下面一段代码为例&#xff0c;基于原型对象&#xff08;Star构造函数的原型对象&#xff09;的继承使得不同构造函数的原型对象关联在一起&#xff08;此处是最大的构造函数Object原型对象&#xff09;&#xff0c;并且这种关联的关系是一种链…

目标检测——YOLOv10算法解读

论文&#xff1a;YOLOv10: Real-Time End-to-End Object Detection (2024.5.23) 作者&#xff1a;Ao Wang, Hui Chen, Lihao Liu, Kai Chen, Zijia Lin, Jungong Han, Guiguang Ding 链接&#xff1a;https://arxiv.org/abs/2405.14458 代码&#xff1a;https://github.com/THU…

购物网站系统

摘 要 随着互联网的快速发展&#xff0c;不同的平台软件也不断涌出市场&#xff0c;在众多的平台中&#xff0c;购物网站深受人们的欢迎&#xff0c;也成为生活中不可缺少的一部分。经过对国内外购物情况的调查&#xff0c;社区购物在近几年来成为电商发展的新趋势&#xff0c…

Vue - 第3天

文章目录 一、Vue生命周期二、Vue生命周期钩子三、工程化开发和脚手架1. 开发Vue的两种方式2. 脚手架Vue CLI基本介绍&#xff1a;好处&#xff1a;使用步骤&#xff1a; 四、项目目录介绍和运行流程1. 项目目录介绍2. 运行流程 五、组件化开发六、根组件 App.vue1. 根组件介绍…

shell数组

shell数组 文章目录 shell数组数组数组遍历冒泡排序 数组 定义&#xff1a;在集合中指定多个元素&#xff1a;元素的类型&#xff1a;整数。字符串&#xff0c;可以是浮点 作用&#xff1a;一次性的定义多个元素&#xff0c;可以为变量赋值提供便利。 数组的定义方法 数组名…

富唯智能打造的AGV搬运机器人转运机器人

AGV搬运机器人&转运机器人 AGV搬运机器人&#xff0c;内部搭载ICD系列核心控制器&#xff0c;拥有不同的移载平台&#xff0c;负载最高可达 1000kq;重复精度高达5mm;支持 Wi-Fi漫游&#xff0c;实现更稳健的网络数据交互;无轨化激光 SLAM 导航&#xff0c;配合 3D 避障相机…

Flutter-无限循环滚动标签

1. 序章 在现代移动应用开发中&#xff0c;滑动视图是常见的交互模式之一。特别是当你需要展示大量内容时&#xff0c;使用自动滚动的滑动视图可以显著提升用户体验。在这篇文章中&#xff0c;我们将讨论如何使用 Flutter 实现一个自动滚动的列表视图。 2. 效果 3. 实现思路 …

[Linux] 历史根源

UNIX系统&#xff1a; 1969年&#xff0c;由贝尔实验室的K.Thompson和D.M.Ritchie为PDP-7机器编写的一个分时操作系统&#xff0c; 最初使用汇编语言编写&#xff0c; 后来1972年C语言出世以后&#xff0c;二人由使用C写了UNIX3&#xff0c; 此后UNIX大为流行开来 UNIX流派树&a…

凌凯科技冲刺上市:2023年业绩反弹,靠关联交易助推业务发展?

近日&#xff0c;上海凌凯科技股份有限公司&#xff08;下称“凌凯科技”&#xff09;向港交所递交上市申请&#xff0c;华泰国际担任其独家保荐人。 透过招股书不难看出&#xff0c;在化学合成一体化这个虹吸效应显著的细分赛道中&#xff0c;凌凯科技拥有头部玩家的先发优势…

数据分析第十三讲:数据可视化入门(二)

数据可视化入门&#xff08;二&#xff09; 本章我们尝试用 matplotlib 来绘制一些高阶统计图表。正如前面所说的&#xff0c;大家可以通过 matplotlib 官方网站上提供的文档和示例来学习如何使用 matplotlib 并绘制出更加高级的统计图表&#xff1b;尤其是在定制一些比较复杂…

人工智能中的监督学习和无监督学习

欢迎来到 Papicatch的博客 目录 &#x1f349;引言 &#x1f349;监督学习 &#x1f348;基本思想 &#x1f348;具体过程 &#x1f34d;数据收集 &#x1f34d;数据预处理 &#x1f34d;模型选择 &#x1f34d;模型训练 &#x1f34d;模型评估 &#x1f34d;模型部署…

【深度学习基础】详解Pytorch搭建CNN卷积神经网络LeNet-5实现手写数字识别

目录 写在开头 一、CNN的原理 1. 概述 2. 卷积层 内参数&#xff08;卷积核本身&#xff09; 外参数&#xff08;填充和步幅&#xff09; 输入与输出的尺寸关系 3. 多通道问题 多通道输入 多通道输出 4. 池化层 平均汇聚 最大值汇聚 二、手写数字识别 1. 任务…

[C++][数据结构][图][下][最短路径]详细讲解

目录 1.最短路径1.单源最短路径 -- Dijkstra算法2.单源最短路径 -- Bellman-Ford算法3.多源最短路径 -- Floyd-Warshall算法原理 1.最短路径 最短路径问题&#xff1a;从在带权有向图G中的某一顶点出发&#xff0c;找出一条通往另一顶点的最短路径&#xff0c;最短也就是沿路径…

spark学习总结

系列文章目录 第1天总结&#xff1a;spark基础学习 1- Spark基本介绍&#xff08;了解&#xff09;2- Spark入门案例&#xff08;掌握&#xff09;3- 常见面试题&#xff08;掌握&#xff09; 文章目录 系列文章目录前言一、Spark基本介绍1、Spark是什么1.1 定义1.2 Spark与M…

valgrind工具的交叉编译及使用

一 概述 valgrind是一款非常好用的工具&#xff0c;用于检测内存泄漏等&#xff0c;这里讲述如何将其交叉编译到arm开发板及如何使用 【C/C 集成内存调试、内存泄漏检测和性能分析的工具 Valgrind 】Linux 下 Valgrind 工具的全面使用指南 - 知乎 (zhihu.com) valgrind: fai…

60.指针数组和数组指针

一.指针数组 指针数组是一个数组&#xff0c;在指针数组中存放的是指针变量。 定义一个指针数组p int *p[5]; 内存模型如下&#xff1a; 指针数组的初始化 #include <stdio.h>int main(void) {int a1;int b2;int c3;int i;int *p[3] {&a,&b,&c};for(i0…

Unbounded CKKS for Bits NTT with Composite Modulus

参考文献&#xff1a; [CHKKS18] Cheon J H, Han K, Kim A, et al. Bootstrapping for approximate homomorphic encryption[C]//Advances in Cryptology–EUROCRYPT 2018: 37th Annual International Conference on the Theory and Applications of Cryptographic Techniques…

技术差异,应用场景;虚拟机可以当作云服务器吗

虚拟机和云服务器是现在市面上常见的两种计算资源提供方式&#xff0c;很多人把这两者看成可以相互转换或者替代的物品&#xff0c;实则不然&#xff0c;这两种资源提供方式有许多相似之处&#xff0c;但是也有不少区别&#xff0c;一篇文章教你识别两者的技术差异&#xff0c;…

RabbitMQ实践——交换器(Exchange)和绑定(Banding)

大纲 direct型交换器默认交换器命名交换器 fanout型交换器topic型交换器headers型交换器 RabbitMQ在概念上由三部分组成&#xff1a; 交换器&#xff08;Exchange&#xff09;&#xff1a;负责接收消息发布者发布消息的结构&#xff0c;同时它会根据“绑定关系”&#xff08;Ba…