【JavaEE多线程】理解和管理线程生命周期

目录

    • Thread
      • Thread类的常用构造方法
      • Thread类的常见属性
      • 启动一个线程-start()
      • 终止一个线程
      • 等待一个线程-join()
      • 线程的状态


Thread

Thread 就是在 Java 中,线程的代言人。系统中的一个线程,就对应到 Java 中的一个 Thread 对象。围绕线程的各种操作,都是通过 Thread 来展开的

Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联

用我们上面的例子来看,每个执行流,也需要有一个对象来描述,类似下图所示,而 Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。

在这里插入图片描述

Thread类的常用构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target, Strin name)使用 Runnable 对象创建线程对象,并命名
Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("这是我的名字");
Thread t4 = new Thread(new MyRunnable(), "这是我的名字");```

Thread类的常见属性

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  1. ID(getId):线程的身份表示(在JVM这里给线程设定的身份标识),一个线程可以有多个身份标识

  2. 名称(getName):各种调试工具用到

  3. 状态(getState):Java中的线程状态和操作系统中有一定差异

  4. 优先级(getPriority):设置/获取线程优先级作用不是很大,线程的调度主要还是系统内核来负责的,系统调度的速度实在太快

  5. 是否后台线程(isDaemon)

    • 后台线程/守护线程:不太影响进程结束

    • 前台线程:会影响进程结束,如果前台线程没执行完,进程是不会结束的

    • 一个进程中所有的前台线程都执行完,退出了,此时即使存在后台线程仍然没执行完也会随着进程一起退出

    • 影响进程退出的就是前台,不影响的就是后台

    • 创建的线程默认是前台线程,通过setDaemon显式的设置成后台

  6. 是否存活(isAlive):Thread对象,对应的线程(系统内核中)是否存活。

    • Thread对象的生命周期,并不是和系统中的线程完全一致的
  7. 是否被中断(isInterrupted):看下面

启动一个线程-start()

  1. start方法,在系统中真正创建出线程
    1. 创建出PCB
    2. 把PCB加入到对应链表
  2. 操作系统内核=内核+配套的程序
  3. 内核:一个系统最核心的功能
    1. 对下,管理好各种硬件设备
    2. 对上,给各种程序提供稳定的运行环境
  4. start方法本身执行成功是一瞬间的,只是告诉系统你要创建一个线程,调用完start后,代码就会立即继续执行start后续的逻辑

终止一个线程

  1. 一个线程的run方法执行完毕,就算终止了

  2. 此处的终止线程,就是想办法让run方法能够尽快执行完毕

  3. 方法:

    1. 程序员手动设定标志位,通过这个来让run尽快结束
    private static class MyRunnable implements Runnable {
        public volatile boolean isQuit = false;
    
        @Override
        public void run() {
            while (!isQuit) {
                System.out.println(Thread.currentThread().getName()
                        + ": 别管我,我忙着转账呢!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()
                    + ": 啊!险些误了大事");
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        System.out.println(Thread.currentThread().getName()
                + ": 让李四开始转账。");
        thread.start();
        Thread.sleep(10 * 1000);
        System.out.println(Thread.currentThread().getName()
                + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
        target.isQuit = true;
    }
    
    1. 直接Thread类,给我们提供好了现成的标志位,不用手动设置标志位
    private static class MyRunnable implements Runnable {
        @Override
        public void run() {
            // 两种方法均可以
            while (!Thread.interrupted()) {
                //while (!Thread.currentThread().isInterrupted()) {
                System.out.println(Thread.currentThread().getName()
                        + ": 别管我,我忙着转账呢!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println(Thread.currentThread().getName()
                            + ": 有内鬼,终止交易!");
                    // 注意此处的 break
                    break;
                }
            }
            System.out.println(Thread.currentThread().getName()
                    + ": 啊!险些误了大事");
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        System.out.println(Thread.currentThread().getName()
                + ": 让李四开始转账。");
        thread.start();
        Thread.sleep(10 * 1000);
        System.out.println(Thread.currentThread().getName()
                + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
        thread.interrupt();
    }
    
  4. 当sleep被唤醒以后,程序员可以有以下几种操作方式:

    1. 立即停止循环,立即结束线程(直接break)
    2. 继续做点别的事情,过一会儿再结束线程(catch中执行别的逻辑,执行完再break)
    3. 忽略终止的请求,继续循环(不写break)
  5. thread 收到通知的方式有两种:

    1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通知,清除中断标志
      • 当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择忽略这个异常, 也可以跳出循环结束线程
    2. 否则,只是内部的一个中断标志被设置,thread 可以通过
      • Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
      • Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志

等待一个线程-join()

  1. 多个线程是并发执行的。具体的执行过程都是由操作系统负责调度的。操作系统的调度线程的过程,是“随机”的。无法确定线程执行的先后顺序
  2. 等待线程,就是一种规划 线程结束 顺序的手段
  3. 注意:join()方法也会抛出Interrupted异常
  4. 谁调用join方法,谁就强占cpu资源,直至执行结束
  5. A B两个线程,希望B先结束A后结束,此时就可以让A线程中调用B.join()的方法。此时,B线程还没执行完,A线程就会进入"阻塞"状态。就相当于给B留下了执行的时间。B执行完毕之后,A再从阻塞状态中恢复回来,并且继续往后执行。如果A执行到B.join()的时候,B已经执行完了,A就不必阻塞了,直接往下执行就可以了
  6. 阻塞:让代码暂时不继续执行了(该线程暂时不去CPU上参与调度)
  7. sleep也能让线程阻塞,阻塞是有时间限制的
  8. join的阻塞,则是“死等”“不见不散”
  9. sleep、join、wait…产生阻塞之后,都是可能被interrupt方法唤醒的,这几个方法都会在被唤醒之后自动清除标志位(和sleep类似),这些方法都会抛出Interrupted异常

线程的状态

  • 先谈谈进程里PCB里的状态字段:就绪阻塞状态(这些是系统设定的状态,Java又把这些细分了)
  • 以下则是线程的状态:
  1. NEW**(开始前)**: 安排了工作, 还未开始行动 (Thread对象创建好了,但还没有调用start()方法)

  2. RUNNABLE**(就绪状态): 可工作的. 又可以分成正在工作中即将开始工作**

    1. 线程正在CPU上运行

    2. 线程正在排队,随时可以去CPU运行

  3. BLOCKED**(阻塞状态)**: 这几个都表示排队等着其他事情 :因为锁

  4. WAITING**(阻塞状态)**: 这几个都表示排队等着其他事情 :因为调用了wait

  5. TIMED_WAITING**(阻塞状态)**: 这几个都表示排队等着其他事情 :因为调用了sleep

  6. TERMINATED**(结束后)**: 工作完成了

  • 线程状态转换图

在这里插入图片描述

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

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

相关文章

Windows下安装myBase Desktop 8

下载 官网下载: Latest Version Downloads 安装 1.下载好安装包后,直接解压用鼠标双击安装文件“Mybase-Desktop-Ver8218-Win64.exe”进入安装向导 2.点击选择“Iaccept the agreement”同意相关协议,随后点击“next” 3.点击“next” 4.选择安装位置&am…

uni-app的页面中使用uni-map-common的地址解析(地址转坐标)功能,一直报请求云函数出错

想在uni-app的页面中使用uni-map-common的地址解析(地址转坐标)功能,怎么一直报请求云函数出错。 不看控制台啊,弄错了控制台,就说怎么一直没有打印出消息。 所以开始换高德地图的,昨天申请了两个 一开始用的第二个web…

Linux:Zabbix + Grafana10.4.2(3)

1.部署zabbix 下面这篇文章写了详细的部署zabbix过程 ,使用的centos9系统 Linux:部署搭建zabbix6(1)-CSDN博客https://blog.csdn.net/w14768855/article/details/137426966?spm1001.2014.3001.5501下面这篇文章使用的是centos7…

HBuilderX 的 CLI 命令行工具

1. cli 介绍 官方介绍:开发者可以通过 cli 命令行指示HBuilderX进行启动、打包、登录等操作 2. 快速启动 Mac 如果 shell 是 zsh,进入终端,在环境变量文件 ~/.zshrc 中添加以下内容,重新打开终端生效 alias hbopen $1 -a /Appli…

【蓝桥杯 2018 省】分数 题解(Excel+提交答案)

问题描述 求等比数列 1 / 1 1 / 2 1 / 4 1 / 8 1 / 16 … 1/1 1/2 1/4 1/8 1/16 \ldots 1/11/21/41/81/16… 的和,其中每项是前一项的一半,如果一共有20项,求这个和是多少,结果用分数表示出来。例如,对于前…

智慧公厕功能与应用

智慧公厕是智慧城市建设中极为重要的组成部分,它以其先进的功能和智能化的应用,为市民提供舒适、便利、安全的卫生设施。下面将以智慧公厕源头实力厂家广州中期科技有限公司,大量精品案例项目现场实景实图实例,深入探讨智慧公厕的…

openGauss 之min/max 优化代码走读

一. 前言 在openGuass中,如果对索引列执行max/min操作,openGauss会优化成只读取索引的最前/后的一行数据,避免了对整表数据进行读取和聚合操作,如下所示: 二. min/max优化代码走读 1. 首先需要将min/max 算子转成成执行计划中降序…

ESP-IDF移植lvgl 驱动 ST7789

文章目录 1 前言2 准备3 移植LVGL3.1 工程准备3.2 修改 CMakeLists.txt文件编译 LVGL3.3 编译LVGL 4 编译 ST7789 LCD驱动5 发现问题 1 前言 本教程开始学习 LVGL的,开始之前要把环境配置好,首先就需要移植 lvgl,使用的是 esp32 环境&#xf…

vmware安装win10及ubuntu

安装win10 新建一个文件夹 选择刚才创建的文件夹 选择需要保存文件的位置,还是选择刚才创建的文件夹 选择自定义硬件 选择下载的win10镜像iso文件,导入后,点击完成即可 接下来就是下一步 没有此电脑,可以点击个性化-》主题-》桌面设置…

分类预测 | Matlab实现SSA-LSSVM麻雀算法优化最小二乘支持向量机数据分类预测

分类预测 | Matlab实现SSA-LSSVM麻雀算法优化最小二乘支持向量机数据分类预测 目录 分类预测 | Matlab实现SSA-LSSVM麻雀算法优化最小二乘支持向量机数据分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现SSA-LSSVM麻雀算法优化最小二乘支持向量机数据…

Nginx日志格式化和追踪

背景 Nginx是一款功能强大的Web服务器,对于网络环境中的日志记录和配置至关重要。定制化Nginx日志格式可以帮助管理员更好地监控服务器性能、分析用户行为并做出相应优化。在本文中,我们将深入探讨Nginx日志格式的高级定制化策略,包括理解基…

【Unity+Python】如何通过Socket进行通信

1、Unity端创建名为UnityClient.cs脚本代码(客户端): 注意:unity的规则中类,名和脚本文件名需要相同。 using System.Net.Sockets; using System.Text; using UnityEngine;public class UnityClient : MonoBehaviour {TcpClient client;Netw…

全景剖析SSD SLC Cache缓存设计原理-2

四、SLC缓存对SSD的寿命是否有优化? 当使用QLC或TLC NAND闪存并将其切换到SLC模式进行写入时,会对闪存的寿命产生以下影响: 短期寿命提升: SLC模式下,每个存储单元仅存储一个比特数据,相对于QLC或TLC来说…

在 Elasticsearch 中扩展 ML 推理管道:如何避免问题并解决瓶颈

作者:来自 Elastic Iulia Feroli 是时候考虑语义搜索运营了吗? 无论你是一位经验丰富的搜索工程师,希望探索新的人工智能功能,还是一位机器学习专家,希望更多地利用搜索基础设施来增强语义相似性模型 —— 充分利用这…

python统计分析——用sklearn进行回归

参考资料:python统计分析【托马斯】 scikit-learn提供了简单而有效的数据挖掘和数据分析工具,包括监督和无监督学习。它提供了如下工具: 分类:辨别出新的观测值应该属于哪一组类别。 回归:对一个新的例子预测一个连续值…

Rust腐蚀服务器常用参数设定详解

Rust腐蚀服务器常用参数设定详解 大家好我是艾西,一个做服务器租用的网络架构师上期我们分享了rust腐蚀服务器的windows系统搭建方式,其中启动服务器bat参数因为涉及的东西比较多所以想通过这篇文章给大家做一下详细的分享。 (注本文中xxxx…

基于 FPGA 的 DE1-SoC 功率估算器

Introduction 功耗是当今许多技术都要考虑的重要因素。例如,手机生产商总是谈论他们在电源管理方面的改进,以及如何延长电池的使用寿命。功能与功耗之间的平衡是许多人都在研究的有趣课题。然而,当我们做实验时,我们很少会考虑我…

【Godot4.2】CanvasItem绘图函数全解析 - 8.绘制点索引

概述 在示意图绘制过程中或者测试过程中,可能需要标记点的索引。 最常见的形式就是用一个圆圈作为背景,用阿拉伯数字作为索引。 实现的重点是动态计算背景圆的半径。原理是,获取字符串的矩形,取对角线长度的一半作为外接圆的半…

【JavaScript | RegExp】正则表达式

本文原创于CSDN秋说,未经授权,不得转载。 文章目录 定义特殊字符元字符字符表格汇总特殊结构标记优先级实例匹配常见的 HTTP 或 HTTPS URL匹配路径匹配URL的各个部分全局搜索邮箱正则表达式日期匹配正则表达式特殊字段匹配正则表达式匹配邮箱正则表达式用…

在Windows中用命令行编译C项目

在Windows中可以用命令行编译C项目 官方指导文档: 演练:在命令行上编译 C 程序 | Microsoft Learn 在官方文档中可以看到,可以只安装VS的命令行工具集,如下图所示