零基础学Java多线程:深入理解线程生命周期

环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8

前言

  只要是科班出身的同学都清楚地知道,在计算机科学领域,多线程它是极为常见的概念,比如线程与进程等基本概念,二者之间有何区别,这都不言而喻了吧。对于多线程,我们在上一章节就讲过了,它可以同时执行多个任务,提高我们开发的程序性能和响应速度。而且Java作为一门广泛使用的开发语言,对多线程提供了强有力的支持。即,本篇文章我们将重点介绍线程的一个新知识点--生命周期,以及实际中我们需要如何使用多线程来实现并发开发。

摘要

  本文旨在帮助零基础的小白同学了解多线程的概念和原理,以及如何在Java中利用多线程进行并发编程,同时也帮助初学者及时温习相关知识点,以免只停留在会用但不懂其原理的层面上。我会通过深入通过案例分析和实际应用场景案例,完整的带着同学们学习并掌握多线程编程的基本原则和技巧。

概述

  既然大家都清楚,对于多线程而言,它是指同时执行多个线程的并发编程模型,而且每个线程都是独立的执行路径,拥有自己的堆栈和程序计数器,线程之间则是通过共享的内存进行通信和协调。所以为什么说Java对多线程提供了强有力的支持,这里就提一嘴,它提供了丰富的API和工具来管理线程的生命周期、同步访问共享资源、处理线程间的通信等,开发语言就已经为某些场景做好了预备工作。

案例演示

如何创建线程?

  在Java中,创建线程的方式非常之多,其中我来通过实例演示其中两种方式:继承Thread类和实现Runnable接口,这两种也是最为简单且经典的实现方式,大家无论如何都必须掌握,学不会理解不深入,那就真会被同行给嘲讽的。针对方式一,它继承Thread类需要重写run()方法,而实现Runnable接口需要实现run()方法。

  下面是一个简单的示例,分别讲如上实现创建线程的方式通过示例代码演示了一波,仅供参考:

  • 继承Thread
 

java

复制代码

/** * @Author bug菌 * @Source 公众号:猿圈奇妙屋 * @Date 2024-04-15 22:23 */ public class MyThread extends Thread { @Override public void run() { // 线程执行的代码逻辑 } } }

  • 实现Runnable接口
 

java

复制代码

/** * @Author bug菌 * @Source 公众号:猿圈奇妙屋 * @Date 2024-04-15 22:24 */ public class MyRunnable implements Runnable { @Override public void run() { // 线程执行的代码逻辑 } }

如何启动线程?

  在创建线程后,并不是就可以直接使用,我们是需要通过一把钥匙来将锁打开,这样线程才能处于启动的状态。所以,这里,我们的钥匙就是,start()方法,我们只需要将其方法进行调用,便可以启动线程。原理呢,也很简单,就是start()方法会启动一个新的线程,并调用线程的run()方法。

  下面是一个启动示例:仅供参考

 

java

复制代码

public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); }

  即如下是一个演示,这里我就在第一个创建线程的方式中,指定输出一段内容,比如:

 

java

复制代码

@Override public void run() { // 线程执行的代码逻辑 System.out.println("线程执行中..."); }

  看过我第一期的同学肯定都知道,控制台是否会打印内容,且输出啥内容,很明显就是会执行run方法。

在这里插入图片描述

  看到这里的同学,你已经很棒了,但我想说,如上只是开胃小菜,照顾下中途加入的同学们,所以接下来我就要进行此期的内容重点讲解了。

何为线程生命周期?

  对于Java线程,它有多个状态,这些状态就组成了线程的生命周期。那么生命周期究竟有那些?不着急,接着往下看,我会把它的每种状态都梳理的清晰,大家请看,线程的生命周期包括以下几个阶段:

  1. 新建(New):线程被创建但还未启动。
  2. 就绪(Runnable):线程可以被执行,但还没有分配到CPU时间片。
  3. 运行(Running):线程正在执行。
  4. 阻塞(Blocked):线程暂时停止执行,等待某些条件的满足。
  5. 等待(Waiting):线程等待其他线程的通知,直到被唤醒。
  6. 超时等待(Timed Waiting):线程等待其他线程的通知,但有一个超时时间。
  7. 终止(Terminated):线程已经执行完毕或因异常退出。

  如下我绘画了一个生命周期简意图,方便大家一目了然了解其生命周期的前后顺序及如何使用,仅供参考。

在这里插入图片描述

  如上图,其实远不止这么简单,我只是大概示意,如果想对这块的内容,针对学习,这里我可以给大家一个学习大纲,按照如下学习步骤,一步一步梳理,就可以把其啃透的。

  • 新建状态(New) -- 创建线程对象的步骤 -- 示例代码
  • 就绪状态(Runnable) -- 调用 start() 方法 -- 就绪状态的定义和工作原理
  • 运行状态(Running) -- 线程从就绪状态到运行状态的转变 -- CPU调度线程执行
  • 阻塞状态(Blocked) -- 线程进入阻塞状态的原因 -- 常见的阻塞情况(如等待I/O、等待锁)
  • 等待状态(Waiting) -- 使用 wait(), join(), sleep() 进入等待状态 -- 等待状态的特点和恢复方式
  • 计时等待状态(Timed Waiting) -- 使用带超时的 wait(), join(), sleep() -- 计时等待状态的特点和应用场景
  • 终止状态(Terminated) -- 线程完成执行或异常退出 -- 终止状态的特点

  这个大纲涵盖了 Java 多线程生命周期的各个方面,提供了全面系统的学习路径。每个部分都可以深入研究和实践,以掌握多线程编程的核心知识。

线程同步

  这里我还要提到一个概念--线程同步。可能小伙伴们都见名知意,但实际上,在多线程编程中,我们经常需要处理共享资源的同步访问。而Java也提供了多种机制来实现线程之间的同步,如使用synchronized关键字、使用Lock接口、使用volatile关键字等,这对于使用多线程的同学来说是十分重要的,后期内容我会着重讲解的,这里只是先抛砖引玉一下,感兴趣的同学可以预先往后自学哦。

应用场景案例

  对于多线程的应用场景,那是非常广泛。下面我给大家梳理了些常见的应用场景案例:仅供参考:

  1. 并行计算:将一个大任务拆分为多个小任务,利用多线程同时进行计算。
  2. 网络编程:处理多个客户端的请求,每个请求可以在一个独立的线程中处理。
  3. 图像处理:对一张图片进行多种滤镜处理,每个滤镜可以在一个独立的线程中处理。
  4. 游戏开发:处理用户的输入和游戏逻辑,可以通过多线程实现游戏的流畅运行。
  5. 数据库操作:通过多线程可以提高数据库查询和更新的效率。

  相信大部分同学貌似都有些的场景没接触过,不过没关系,这里大家只需要知道,这些场景,使用多线程是事半功倍的。

优缺点分析

  如下我对于多线程的优缺点再进行辩证分析,希望能够帮到同学们正确认识多线程。

具有以下优点:

  • 提高程序的响应能力:多线程可以同时执行多个任务,提高程序的响应速度。
  • 更好的利用CPU资源:多线程可以在多个CPU核心上同时执行,充分利用CPU资源。
  • 简化编程模型:通过多线程,我们可以将复杂的任务拆分为多个简单的子任务并进行并发处理。

然而,多线程编程也存在一些缺点:

  • 线程安全性问题:多线程访问共享资源时需要保证线程安全,否则会出现数据竞争和一致性问题。这点也是使用中必会遇到的问题。
  • 线程间的通信复杂性:多线程之间的通信需要经过严格的同步和协调,增加了编程的复杂性。
  • 调试和测试困难:多线程程序的调试和测试比单线程程序更加困难,因为涉及到并发的问题。

类方法介绍

  在多线程编程中,Java提供了一些常用的类和方法来管理线程的生命周期和同步访问共享资源。下面我给大家梳理了些常用的类和方法介绍,展示如下:

  • Thread类:表示一个线程,可以通过继承该类来创建自定义的线程类。
  • Runnable接口:定义了一个线程的任务,可以通过实现该接口来创建线程任务。
  • start()方法:启动一个新的线程。
  • join()方法:等待线程结束。
  • sleep()方法:线程休眠一段时间。
  • yield()方法:暂停当前线程,让出CPU的时间片。
  • wait()方法:使线程等待其他线程的通知。
  • notify()方法:唤醒一个等待的线程。

测试用例

测试代码

  这里我就通过一个简单的测试用例,用来演示如何使用多线程计算斐波那契数列:

 

java

复制代码

/** * @Author bug菌 * @Source 公众号:猿圈奇妙屋 * @Date 2024-04-15 23:12 */ public class FibonacciThread extends Thread { private final int n; public FibonacciThread(int n) { this.n = n; } @Override public void run() { int a = 0, b = 1; for (int i = 0; i < n; i++) { System.out.println(a); int temp = a + b; a = b; b = temp; } } public static void main(String[] args) { FibonacciThread thread = new FibonacciThread(10); thread.start(); } }

测试结果

  针对如上测试代码,这里我本地进行实际测试一波,结果仅供参考,有条件的同学们也可以自己本地实践一下。

在这里插入图片描述

测试代码解析

  针对如上测试代码,这里我再具体给大家讲解下,希望能够更透彻的帮助大家理解。

  如上案例我定义了一个名为FibonacciThread的类,它继承自Thread类,用于生成并打印斐波那契数列的前n个数字。以下是代码的详细分析:

  1. 类定义

    • FibonacciThread类继承自Thread类,这意味着它是一个自定义的线程类,用于执行特定的任务。
  2. 成员变量

    • private final int n;:一个私有的、不可变的成员变量,用于存储斐波那契数列的项数。final关键字表示一旦n被初始化,它的值就不能被改变。
  3. 构造函数

    • public FibonacciThread(int n):这是FibonacciThread类的构造函数,它接收一个整数参数n,并通过this.n = n;将其赋值给成员变量n
  4. 重写run方法

    • @Override public void run():这是FibonacciThread类中的run方法,它重写了Thread类中的run方法。run方法是线程执行的核心方法,当线程被启动时,这个方法将被执行。
    • run方法中,使用一个for循环来生成斐波那契数列。初始化两个整数变量ab分别为0和1,这两个变量用来存储数列中的连续项。
    • 在循环中,首先打印当前的斐波那契数a,然后计算下一项temp = a + b。接着更新ab的值为下一个连续的斐波那契数。
  5. main方法

    • public static void main(String[] args):这是程序的入口点。在main方法中,创建了FibonacciThread类的一个实例thread,并传入参数10,表示生成斐波那契数列的前10项。
    • 调用thread.start()来启动线程。这将创建一个新的执行线程,并在这个线程中执行FibonacciThread类的run方法。

  当程序运行时,它将创建一个线程来计算并打印斐波那契数列的前10项。斐波那契数列是一个著名的数列,每一项都是前两项的和,通常以0和1开始。

  请注意,由于斐波那契数列的增长速度非常快,对于较大的n值,可能会得到非常大的数字。此外,由于线程的调度是由操作系统控制的,所以每次运行程序时,斐波那契数列的打印顺序可能会有所不同。

小结

  借此,我总体给大家梳理下,在本文中,我介绍了Java中的线程生命周期,包括线程的创建、启动、运行、阻塞、等待、终止等阶段。我们还讨论了多线程编程的应用场景、优缺点分析和常用的类和方法。通过学习本文,大家可以掌握多线程编程的基本原理和技巧,特别是了解它的生命周期。

总结

  总的来说,多线程是一种并发编程模型,它可以同时执行多个任务,提高程序的性能和响应速度,这点是毋庸置疑的。Java提供了丰富的API和工具来支持多线程编程。了解线程的生命周期和同步机制对于掌握多线程编程至关重要。希望本文对Java零基础学员学习多线程编程有所帮助。

结尾

  最后,我还要多嘴提一下,多线程是Java开发中非常重要的一部分,它与你日常开发息息相关,如果你掌握不透彻,那么将会是你是否能够进阶Java的指标之一。而日常中,通过合理地使用多线程就可以提高程序的性能和响应能力,压根不需要你额外去考虑其他的解决措施,因为在实际开发中,我们需要根据具体的应用场景选择合适的多线程方式,而不是滥用,这样一定会产生线程安全问题的,所以,这里头的学问多的数不清,其中的线程安全,又是一大知识点,所以说,活到老,学到老,想要干好这行,不学习是不行滴。

... ...

  ok,以上就是我这期的全部内容啦,若想学习更多,你可以持续关注我,我会把这个多线程篇系统性更新。每篇都是实打实的项目实战经验所撰。只要你每天学习一个奇淫小知识,日积月累下去,你一定能成为别人眼中的大佬的!功不唐捐,久久为功!

「赠人玫瑰,手留余香」,咱们下期拜拜~~


原文链接:https://juejin.cn/post/7378535517951213594
 

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值