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

【JavaEE】线程创建和终止,Thread类方法,变量捕获(7000字长文)

阿华代码,不是逆风,就是我疯,你们的点赞收藏是我前进最大的动力!!7000字长文,希望本文内容能够帮助到你!

目录

一:创建线程五种方式

方式一:继承Thread类,再实例化

 方式二:实现Runnable接口,重写run方法

方式三:匿名内部类写法

方式四:Runnable+匿名内部类

方式五:lambda表达式

二:Thread常见方法

1:Thread方法

2:获取Thread属性的方法 

(1)守护进程

(2).setDaemon()方法

①前台/后台线程

②.setDaemon

③结果分析:

(3)isAlive()

(4)start方法和run方法的区别

三:如何提前终止一个线程

1:标志位——isQuit

(1)变量捕获:重点重点重点

(2)lambda复制和传参理解

2:Thread内置变量isinterrupted

(1)isinterrupted本质

(2)sleep清空标志符

(3)解决方式(catch中加代码)


一:创建线程五种方式

方式一:继承Thread类,再实例化

package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-17* Time: 14:20*/
class MyThread extends Thread{@Overridepublic void run() {System.out.println("这就是进入该线程的入口");}
}
public class ThreadDemo1 {public static void main(String[] args) {//根据类,创建实例,线程实例才是真正的线程//一般用向上转型的写法Thread t = new MyThread();t.start();}
}

 方式二:实现Runnable接口,重写run方法

package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 9:20*/
class MyTread3 implements Runnable{@Overridepublic void run() {while(true){System.out.println("这里是run线程");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class TreadDome3 {public static void main(String[] args) {Runnable runnable = new MyTread3();//相当于借刀杀人了Thread t = new Thread(runnable);t.start();while(true){System.out.println("这里是main函数线程");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}

注:可以通过Runnable这个接口,可以抽象出一段被其他实体执行的代码,还是需要搭配Thread类来进行使用

方式三:匿名内部类写法

在实例化Thread对象时{}里创建匿名内部类,重写run方法

匿名内部类:

①没有名字,不能重复使用

②这个新的类继承自Thread,并且{}里可以定义子类的属性和方法

③t的指向不仅仅是Thread,还有它的子类(虽然没名字),(即不仅是Thread的实例,也是其子类的实例)

package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 9:39*/
public class ThreadDome4 {public static void main(String[] args) {Thread thread = new Thread(){public void run(){while(true){System.out.println("这里是由匿名内部类实现的线程");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}};thread.start();while(true){System.out.println("这里是main函数入口");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

方式四:Runnable+匿名内部类

实现Runnable接口,重写run方法实现匿名内部类

package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 10:07*/
public class ThreadDome5 {public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while(true){System.out.println("run method");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});thread.start();while(true){System.out.println("main method");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}

方式五:lambda表达式

lambda表达式,适合简单直观的代码,如果代码过于复杂还是需要提取出来的

在Java中方法的实现依赖于类,方法不能脱离类单独存在,这里就导致为了设置回调函数,不得不套上一层类,但是并不常用——引出了lambda表达式。

函数式接口相当于在没有破坏java原有的规则上(方法不能脱离类单独存在),单独给lambda一个解释

第一个标记的红色方框中的()->  ,()括号中可以带参数

package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 10:29*/
public class ThreadDome55 {public static void main(String[] args) {Thread thread = new Thread(()->{while (true){System.out.println("run method");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});thread.start();while(true){System.out.println("main method");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}

二:Thread常见方法

1:Thread方法

2:获取Thread属性的方法 

后面的代码中会运用到,有相应的解释

(1)守护进程

通过之前的学习,我们知道,main方法走完了,整个进程就结束了。 现在我们引入了线程的概念,那这个结论还准确吗。有没有例外呢? 

下面我们举例:代码里面我们创建main函数线程

这里我们使用jconsole工具来辅助(上一篇博客有讲怎么使用jconsole前面)

package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 10:58*/
public class ThreadDome6 {public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while(true){System.out.println("run method");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}} , "这个线程的名字叫:测试");thread.start();}}

我们可以发现jconsole线程运行详细信息中,没有main函数,但是有我们的测试线程很明显即使main函数这个前台线程已经结束了,但是这个进程依旧还在运行(可以说是这个“这个线程的名字叫:测试”的线程还在运行)

由此我们引出一组概念:前台线程和后台线程

(2).setDaemon()方法

①前台/后台线程

重点:咱们创建的线程,默认都是前台线程,会阻止进程的结束,只要前台线程没有执行完,进程就不会结束,即使main函数这个线程已经执行完毕

(这么理解:后台进程没有话语权,只要还有前台线程,进程就不会结束)

②.setDaemon

理解:Daemon是守护的意思,这个方法是把某线程设置为后台线程(守护线程)

注:这个方法一定要在“.start”方法之前设置

接上文,我们引入.setDaemon()方法,可以将Thread下的线程从前台改为后台,下面会详细解释两者区别。

③结果分析:

什么都没有打印是因为,我们把main函数设置为了后台线程,这个线程走完了,那整个进程都结束了,Thread这个前台线程

(3)isAlive()

isAlive(),方法,表示了当前内核中的线程(pcb)是否还存在,内核中的线程和实例的周期是不一致的

①在创建完Thread对象之后,start方法之前,pcb还没有创建出来,所以答疑结果为false

②在start方法之后,线程结束之前,对象存在,pcb存在,打印结果为true,

③线程run完了,pcb得到释放,为false

④注意下面的代码Thread.sleep(5000) ,如果沉睡时间改为3000ms以下,那么最后一条打印结果就不确定了,线程的随机调度

package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 18:24*/
public class ThreadDemon8 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}});System.out.println(thread.isAlive());//false,有对象,无pcb线程thread.start();//创建线程System.out.println(thread.isAlive());//true,有对象,有pcbThread.sleep(5000);//main函数线程沉睡5s,此时Thread线程3s沉睡完了,thread线程结束,thread对象还在System.out.println(thread.isAlive());//false}}

(4)start方法和run方法的区别

start方法核心是创建一个新的线程,但是run方法仅仅是一个方法、一个线程的入口,类似main方法的入口,两者不能说没有关系,简直是毫无关系!!!

package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 18:56*/
public class ThreadDemon9 {public static void main(String[] args) {Thread t1 = new Thread(){@Overridepublic void run() {while(true){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("run线程方法正在执行");}}};//t1.run();//不屏蔽这行代码,将会一直死循环在run方法中,单线程main的t1.start();System.out.println("main函数线程正在执行");}}

三:如何提前终止一个线程

1:标志位——isQuit

我们需要在Thread实例化中写符合能够控制线程的结构,下面的代码我们引入isQuit这个静态成员变量,来控制while循环,进而达到提前终止线程这样一个目的

/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-19* Time: 19:18*/
public class ThreadDemon12 {private static boolean isQuit = false;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{while(!isQuit){try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("t1线程正在运行");}});t1.start();Thread.sleep(2001);isQuit = true;System.out.println("终止t1线程");}}

(1)变量捕获:重点重点重点

提问:上述代码能否将isQuit这个变量在main方法中定义(局部变量)。不行

在lambda匿名内部类当中有一条规定:lambda匿名内部类可以获取外面定义的成员变量(本质是将外面的成员变量作为参数传进来,这个被捕获的(变量)参数必须是final,或者“事实final”)

大前提这个变量定义在main函数内部

零:解释“事实final”

定义的成员变量虽然没有被final修饰,但是这个成员变量没有被修改过(有点那种“虽无夫妻之名,但有夫妻之实”的感觉)。

举例1:在mian函数内部定义  不加final修饰   的局部变量(可行)

举例2:在mian函数内部定义  不加final修饰  的局部变量  并且修改isQuit的值(不可行,lambda报错)

举例3:在mian函数内部定义  加final修饰  的局部变量  并且修改isQuit的值(不可行,final报错)

(2)lambda复制和传参理解

承接举例1:我们删除isQuit这一行代码

我们都知道,main函数执行完毕,那么main函数中定义的局部变量会进行回收,但是在上述两个线程中,main方法结束了,isQuit已经被回收了,这个Thread(t1)线程为什么还能运行(他线程用到了isQuit作为循环判断条件)。

总结:这里是因为,lambda获得的成员变量,是作为参数传进来的(可以理解为复制拷贝,是一个全新的个体),main方法执行完了,isQuit的栈帧就销毁了,但是Thread(t1)中拷贝过来的isQuit所创建的栈帧还在呀!!!

2:Thread内置变量isinterrupted

(1)isinterrupted本质

利用Thread类的实例内部成员变量,来取代我们在1中使用的,手动创建的静态成员变量isQuit

package thread;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-20* Time: 10:23*/
public class ThreadDemon13 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{while(!Thread.currentThread().isInterrupted()){ //当t1.interrupt();生效,循环条件为false,被打断了try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("t1线程正在运行");}});t1.start();Thread.sleep(2001);t1.interrupt();//让t1被打断,相当于isQuit = trueSystem.out.println("终止t1线程");}
}

 (2)sleep清空标志符

结果分析——

目的:给程序员创造更多的“可操作空间”

运行上述代码,报错,这是因为,我们的中断了t1线程的sleep提前唤醒会做两件事:1:清空标志符,2:抛出InterruptedException异常),sleep把interrupted又设置回false,进而while循环判定条件变成true,最后被catch捕获中断异常。

(3)解决方式(catch中加代码)

①让线程立即结束:加上break;

②让线程不结束:不加break,让它报错

③让线程执行一些代码后再结束:写一些其它代码后,再break。

相关文章:

【JavaEE】线程创建和终止,Thread类方法,变量捕获(7000字长文)

阿华代码,不是逆风,就是我疯,你们的点赞收藏是我前进最大的动力!!7000字长文,希望本文内容能够帮助到你! 目录 一:创建线程五种方式 方式一:继承Thread类,…...

[Python数据可视化] Plotly:交互式数据可视化的强大工具

引言: 在数据分析和可视化的世界中,Plotly 是一颗耀眼的明星。它是一个开源的交互式图表库,支持多种编程语言,包括 Python、R 和 JavaScript。Plotly 的强大之处在于它能够创建出既美观又具有高度交互性的图表,使得数据…...

Excel--DATEDIF函数的用法及参数含义

DATEDIF函数的用法为: DATEDIF(start_date,end_date,unit),start_date表示的是起始时间,end_date表示的是结束时间。unit表示的是返回的时间代码,是天、月、年等。如下: Datedif函数的参数含义unit参数返回值的意义"y"两个时间段之间的整年数…...

执行网络攻击模拟的 7 个步骤

在进攻和防守策略方面,我们可以从足球队和美式足球队身上学到很多东西。球员们会分析对方球队的策略,找出弱点,相应地调整进攻策略,最重要的是,练习、练习、再练习。作为最低要求,网络安全部门也应该这样做…...

技术成神之路:设计模式(十四)享元模式

介绍 享元模式(Flyweight Pattern)是一种结构性设计模式,旨在通过共享对象来有效地支持大量细粒度的对象。 1.定义 享元模式通过将对象状态分为内部状态(可以共享)和外部状态(不可共享)&#xf…...

使用systemctl实现开机自启动jar包

目录 1. 创建服务文件2. 配置服务文件3. 重新加载 systemd 配置4. 启动服务5. 查看服务状态 1. 创建服务文件 创建服务文件: 在 /etc/systemd/system/ 目录下创建一个新的服务文件 myapp.service。 sudo vim /etc/systemd/system/myapp.service2. 配置服务文件 按i…...

2024.9.20营养小题【2】(动态分配二维数组)

这道题里边涉及到了动态分配二维数组的知识点,不刷这道题我也不知道这个知识点,算是一个比较进阶一点的知识点了。 参考:C语言程序设计_动态分配二维数组_哔哩哔哩_bilibili【C/C 数据结构 】二维数组结构解析 - 知乎 (zhihu.com)...

前端web端项目运行的时候没有ip访问地址

我们发现 没有netWork 的地址 导致 团队内其他同学无法打开我们的地址 进行访问 在page.json 中的运行 指令中 添加 --host 记得加上空格 这样我们就可以看到这个地址了 团队其他同学 就可以访问我们这个地址了...

微服务架构陷阱与挑战

微服务架构6大陷阱 现在微服务的基础设施还是越来越完善了,现在基础设施缺乏的问题逐渐被解决了。 拆分粒度太细,服务关系复杂 拆分降低了服务的内部复杂度,但是提升了系统的外部复杂度,服务越多,服务和服务之间的连接…...

react的事件绑定

文章目录 基本示例使用箭头函数事件对象阻止默认行为绑定事件处理函数的上下文 在 React 中,事件绑定主要通过 JSX 属性来实现。事件处理函数被传递给相应的事件属性,例如 onClick、onChange 等。这些属性会被绑定到 HTML 元素上,并在事件发生…...

ASP.NET Core 入门教学二十九 DDD设计

在软件开发中,领域驱动设计(Domain-Driven Design,简称DDD)是一种重要的软件设计方法论,它强调通过深入理解业务领域来构建高质量的软件系统。DDD的核心思想是将复杂的业务逻辑集中在领域模型中,并通过分层…...

Rocprofiler测试

Rocprofiler测试 一.参考链接二.测试过程1.登录服务器2.使用smi获取列表3.使用rocminfo获取Agent信息4.准备测试用例5.The hardware counters are called the basic counters6.The derived metrics are defined on top of the basic counters using mathematical expression7.P…...

基于python flask的高血压疾病预测分析与可视化系统的设计与实现,使用随机森林、决策树、逻辑回归、xgboost等机器学习库预测

研究背景 随着现代社会的快速发展,生活方式的改变和人口老龄化的加剧,心血管疾病,尤其是高血压,已成为全球范围内的重大公共健康问题。高血压是一种常见的慢性疾病,其主要特征是动脉血压持续升高。长期不控制的高血压…...

Lombok 与 EasyExcel 兼容性问题解析及建议

在 Java 开发中,Lombok 被广泛用于减少样板代码,如 Getter、Setter、构造函数等。然而,在与像 EasyExcel 这样依赖反射机制的库一起使用时,可能会遇到一些意想不到的问题。本文将深入探讨 Lombok 与 EasyExcel 之间的兼容性问题&a…...

Kubeadm快速安装 Kubernetes集群

1. Kubernetes简介 Kubernetes(k8s)是谷歌开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。它具有以下特点: 开源容器化自动部署扩展高可用 2. Kubernetes架构 Kubernetes遵循主从式架构设计,主要分…...

OpenJudge | 八皇后问题

总时间限制: 10000ms 内存限制: 65536kB 描述 在国际象棋棋盘上放置八个皇后,要求每两个皇后之间不能直接吃掉对方。 输入 无输入。 输出 按给定顺序和格式输出所有八皇后问题的解(见Sample Output)。 样例输入 (null)样例输出 No. 1 …...

C#往压缩包Zip文件的文件追加数据

C#往压缩包Zip文件的文件追加数据 往一个已经压缩好的压缩包里追加数据,一般就有两种方式,一种是前面已经学习过的,就是追加一个新的文件, 另外一种就是往已经存在的文件追加数据。 往已经存在的文件追加数据,需要先找到文件索引。 在压缩包里声明的名称,与外面的文件路…...

局域网共享文件夹:您没有权限访问,请与网络管理员联系

局域网共享文件夹:您没有权限访问,请与网络管理员联系 win10 1909 专业版背景 我有两个电脑,还有两块外挂硬盘,较大的一块放在老电脑上,为了方便用垃圾百度网盘在里边下载东西,又不污染新电脑的环境。 如…...

科技修复记忆:轻松几步,旧照变清晰

在时间的长河中,旧照片承载着无数珍贵的记忆与故事。然而,随着岁月的流逝,这些照片往往变得模糊不清,色彩黯淡,令人惋惜。 幸运的是,随着科技的发展,我们有了多种方法来修复这些旧照片的画质&a…...

java -versionbash:/usr/lib/jvm/jdk1.8.0_162/bin/java:无法执行二进制文件:可执行文件格式错误

实验环境:Apple M1在VMwareFusion使用Utubun Jdk文件错误  尝试: 1、重新在网盘下载java1.8 2、在终端通过命令下载 3、确保 JDK 正确安装在系统中,可以通过 echo $JAVA_HOME 检查 JAVA_HOME 环境变量是否设置正确。 &#xfff…...

微信小程序云开发平台MySQL的连接方式

注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...

2023赣州旅游投资集团

单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...

Windows 下端口占用排查与释放全攻略

Windows 下端口占用排查与释放全攻略​ 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。​ 一、准…...

python打卡day49@浙大疏锦行

知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 一、通道注意力模块复习 & CBAM实现 import torch import torch.nn as nnclass CBAM(nn.Module):def __init__…...

RKNN开发环境搭建2-RKNN Model Zoo 环境搭建

目录 1.简介2.环境搭建2.1 启动 docker 环境2.2 安装依赖工具2.3 下载 RKNN Model Zoo2.4 RKNN模型转化2.5编译C++1.简介 RKNN Model Zoo基于 RKNPU SDK 工具链开发, 提供了目前主流算法的部署例程. 例程包含导出RKNN模型, 使用 Python API, CAPI 推理 RKNN 模型的流程.   本…...

零基础在实践中学习网络安全-皮卡丘靶场(第十一期-目录遍历模块)

经过前面几期的内容我们学习了很多网络安全的知识,而这期内容就涉及到了前面的第六期-RCE模块,第七期-File inclusion模块,第八期-Unsafe Filedownload模块。 什么是"遍历"呢:对学过一些开发语言的朋友来说应该知道&…...

轻量安全的密码管理工具Vaultwarden

一、Vaultwarden概述 Vaultwarden主要作用是提供一个自托管的密码管理器服务。它是Bitwarden密码管理器的第三方轻量版,由国外开发者在Bitwarden的基础上,采用Rust语言重写而成。 (一)Vaultwarden镜像的作用及特点 轻量级与高性…...

华硕电脑,全新的超频方式,无需进入BIOS

想要追求更佳性能释放 或探索更多可玩性的小伙伴, 可能会需要为你的电脑超频。 但我们常用的不论是BIOS里的超频, 还是Armoury Crate奥创智控中心超频, 每次调节都要重启,有点麻烦。 TurboV Core 全新的超频方案来了 4不规…...