「JavaEE」线程状态

🎇个人主页:Ice_Sugar_7
🎇所属专栏:JavaEE
🎇欢迎点赞收藏加关注哦!

线程状态

  • 🍉start 和 run 的区别
  • 🍉终止线程
  • 🍉join & 阻塞状态
  • 🍉线程六大状态

🍉start 和 run 的区别

这是一个经典的面试题,以下面代码为例:

public class MyThread extends Thread{@Overridepublic void run() {System.out.println("hello");}public static void main(String[] args) {Thread t = new MyThread();t.start();t.run();}
}

可以看到结果都输出“hello”
在这里插入图片描述
这两者的区别在于:
调用start创建一个新的线程,由这个线程执行打印 hello 的任务;
t.run() 则是调用 Thread 实例中的 run 方法,这个操作是在 main 主线程中打印 hello

如果我们把代码改成下面这样:在 run 方法和 main 方法中写个死循环,此时 t.run() 就只打印 hello thread,主线程没办法再向下执行

public class MyThread extends Thread{@Overridepublic void run() {while(true) {System.out.println("hello thread");}}public static void main(String[] args) {Thread t = new MyThread();t.run();while(true) {System.out.println("hello main");}}
}

🍉终止线程

一个线程,它的 run 方法如果执行完毕,那么它就终止了
如果我们想让线程提前终止,那就需要让 run 方法能够提前结束。我们一般会引入标志位,在其他进程中修改标志位的值来结束进程
也就是说:线程 A 什么时候结束,取决于另一个线程 B 什么时候修改 A 的标志位的值

Thread 实例提供的 currentThread 方法可以用来获取当前线程实例。也就是说哪个线程调用这个方法,得到的就是哪个线程的实例(类似 this)
比如下面这个代码,我们先看 while 循环

while(!Thread.currentThread().isInterrupted()) {     //...
}

isInterrupted 方法是用来查看当前线程是否被中断。如果一个线程被中断,那么得到的结果就为 true,它其实就相当于标志位
通过实例.interrupt() 可以中断线程

public class MyThread{public static void main(String[] args) throws InterruptedException{Thread t = new Thread(()-> {while(!Thread.currentThread().isInterrupted()) {System.out.println("线程运行中");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("线程执行完毕");});t.start();Thread.sleep(3000);//让 t 线程结束t.interrupt();}
}

看下结果:
在这里插入图片描述
可以看到代码出现异常之后,t 线程还在打印,这说明它并没有真正结束
而如果删掉匿名内部类中的 sleep,那么 interrupt 可以让线程顺利结束:

public static void main(String[] args) throws InterruptedException{Thread t = new Thread(()-> {while(!Thread.currentThread().isInterrupted()) {System.out.println("线程运行中");}System.out.println("线程执行完毕");});t.start();Thread.sleep(2000);t.interrupt();
}

在这里插入图片描述

那就说明 sleep 导致结果和预期结果不同
在执行 sleep 的过程中,调用 interrupt,可能会导致 sleep 的休眠时间还没到,就被提前唤醒
被提前唤醒后,会做两件事:
①抛出 InterruptedException (这个异常紧接着就会被 catch 捕获到)
②清除 Thread 对象的 isInterrupted 标志位

在上面的代码中,我们已经通过 Interrupt 方法把标志位设为 true 了,但是 sleep 被提前唤醒后就把标志位设回 false,所以导致循环继续执行
如果想让线程结束,只需在 catch 中加上 break 就 ok 了:

while(!Thread.currentThread().isInterrupted()) {System.out.println("线程运行中");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
}

当然,其实不止 sleep 有清空标志位的机制,很多方法都会这样

清空标志位是为了给我们更多的操作空间
比如上一行代码写的是 sleep(1000),但是现在1000ms 还没到就要终止线程,这样就前后矛盾了,此时就需要抛出异常,然后对这种情况进行具体的处理
我们可以在 catch 语句中加入一些代码来做处理:

  1. 让线程立即结束:加上 break
  2. 让线程继续执行:不加 break
  3. 让线程执行一些逻辑之后再结束:写一些其他代码,再 break

idea 生成的 catch 语句里面自动给的代码是 e.printStackTrace(),这个是在打印调用栈,或者是抛出另外一个异常。实际开发中这两种代码只是纯纯占个位置而已,没啥卵用


🍉join & 阻塞状态

虽然多个线程之间的执行顺序是不确定的,但是我们可以在应用程序中通过一些 api 来影响线程执行的顺序

join 就是一种方式,也是线程最核心的 api 之一,它通过影响线程结束的先后顺序来影响总的执行顺序
比如让 main 线程等待 t 线程,那就在 main 线程中调用 t.join()
执行 join 的时候,会看 t 线程是否正在运行
如果 t 正在运行,那么 main 线程就会阻塞(暂时不参与 CPU 执行)
如果 t 运行结束,那么 main 就会从阻塞中恢复过来,继续向下执行

由此可以看出:阻塞使这两个线程的结束时间产生先后顺序

在上面的例子中,就一定是 t 先结束,然后才是 main 结束
实际开发中一般不止 t 和 main 这两个线程,t 线程虽然可能是和其他线程共同进行调度的,但由于主线程一直处于等待状态,所以即使 t 中间经历多次 CPU 的切换,最终也能顺利执行完毕

join 的一个典型应用就是使用多个线程并发进行一系列计算,让一个线程阻塞等待上述计算线程,等到所有线程都计算完了,再让这个线程汇总结果
举个例子,弄两个线程,合作计算 1 到 100w 的和(一个线程计算 50w 个数),最后在 main 线程中打印结果:

public class MyThread{public static long sum = 0;public static void main(String[] args) throws InterruptedException{Thread t1 = new Thread(()-> {for(long i = 1;i <= 50_0000L;i++) sum += i;});Thread t2 = new Thread(()-> {for(long i = 50_0001L;i <= 100_0000L;i++) sum += i;});t1.start();t2.start();t1.join();t2.join();System.out.println(sum);}
}

在这里插入图片描述
在这里插入图片描述
不过这个结果貌似不太对,因为两次算出来的 sum 不一样,这就涉及到后面要讲的线程安全问题,不过这是后话,现在只需知道弄多个线程分别运算的效率,会比单独一个线程运算的效率高就 ok 了

然后我们在调用 join 的时候,可以看到它其实有三个重载的方法

在这里插入图片描述
millis 和 nanos 分别是毫秒和纳秒,不过因为系统的时间没法精确到纳秒级别,所以没啥卵用

如果参数不填时间(也就是第一个重载方法),那称为“死等”,就是说某个线程一定要等到另一个线程执行完才会继续向下执行。但是这种逻辑其实是不科学的,因为如果代码中因为死等导致程序卡住了,那就无法处理后续的逻辑,这就是非常严重的 bug 了
如果参数填了时间,那则是带有超时时间的等待,如果等待的时间超过超时时间,那就不会再等了,继续执行


🍉线程六大状态

Java 中线程的状态可分为:

  1. NEW:已经创建好了 Thread 对象,但是还没有调用 start 方法在系统中创建线程(只有处于 NEW 状态才能 start,并且一个 Thread 对象只能 start 一次)
  2. TERMINATED:系统内部的线程执行完毕
  3. RUNNABLE:就绪状态,表示这个线程正在 CPU 上执行,或者随时都可以去 CPU 上执行
  4. TIMED_WAITING:指定时间的阻塞,到达一定时间之后会自动解除阻塞,使用 sleep 或 带有超时时间的 join 会进入这个状态
  5. WAITING:不带时间的阻塞(死等),必须满足一定条件才会解除阻塞,使用 join 或者 wait 会进入这个状态
  6. BLOCKED:由于锁竞争引起的阻塞(后面说到线程安全时会详细介绍)

可以用一幅图来表示这六个状态间的联系:
在这里插入图片描述

这些状态在我们调试多线程代码的 bug 时可以作为重要参考依据
比如我们常说“程序卡住了”,这就说明一些关键的线程出现阻塞,我们可以通过观察线程的状态分析出一些原因

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker 基本命令

目录 一、docker 镜像操作命令 1.1.查询软件镜像 1.2.docker pull&#xff1a;下载镜像 1.3.docker push&#xff1a;上传镜像 1.4.docker images&#xff1a;查看本地镜像 1.5.docker inspect &#xff1a;获取镜像详细信息 1.6.docker tag&#xff1a;添加镜像标签 …

Git:使用conda命令切换虚拟环境

1. 问题 在win10电脑的Git中&#xff0c;无法使用conda list命令&#xff0c;报错&#xff08;bash&#xff1a;conda&#xff1a;command not found&#xff09;。也无法使用conda activate base命令激活虚拟环境&#xff0c;报错&#xff08;bash&#xff1a;conda&#xff…

共享单车数据分析与需求预测项目

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 项目背景 自动自行车共享系统是传统自行车租赁的新一代&#xff0c;整个会员、租赁和归还过程都变得自动化。通过这些系统&#xff0c;用户可以…

L1-098 再进去几个人 - java

L1-098 再进去几个人 代码长度限制 16 KB 时间限制 400 ms 内存限制 64 MB 栈限制 8192 KB 题目描述&#xff1a; 数学家、生物学家和物理学家坐在街头咖啡屋里&#xff0c;看着人们从街对面的一间房子走进走出。他们先看到两个人进去。时光流逝。他们又看到三个人出来。 物理…

锐捷网络闪耀高博会:智慧教育数字基座引领教育数字化新浪潮

4月15日,第61届中国高等教育博览会(简称“高博会”)在福州盛大开幕,在这次教育高端装备展示、教学改革成果交流、校企云集的行业盛会上,围绕构建智慧教育数字基座,锐捷网络携全场景智慧教育方案亮相,极简以太全光网、高校桌面云、5G多网融合等创新方案纷纷登场,吸引了众多观众驻…

【Python_PySide6学习笔记(三十六)】基于QGroupBox和QScrollArea实现带有滚动条的QGroupBox(分组框)

基于QGroupBox和QScrollArea实现带有滚动条的QGroupBox分组框 基于QGroupBox和QScrollArea实现带有滚动条的QGroupBox(分组框)前言正文1、创建QGroupBox并创建其内部布局2、创建QScrollArea并将QGroupBox设置为其内容3、将QScrollArea添加到主窗口的中心部件的布局中4、完整代码…

Linux实现文件共享

#nfs-utils、rpcbind 软件包来提供 NFS 共享服务 #客户端创建共享文件夹&#xff1a; nmcli c reload nmcli c up ens160 systemctl stop firewalld systemctl disable firewalld rpm -q nfs-utils rpcbind #查看是否安装 systemctl enable rpcbind systemctl enable nfs…

JavaEE初阶之IO流快速顿悟一(超详细)

目录 题外话 正题 IO流 Java.io.FileInputStream int read() int read(byte[] b) 关于异常 Java7的新特性: try-with-resources ( 资源自动关闭) Java.io.FileOutputStream void write(int b) void write(byte[] b) 小结 题外话 十年青铜无人问,一朝顿悟冲王者 前天…

C#控制台相关方法

控制台相关方法 文章目录 控制台输入1、清空2、设置控制台3、设置光标位置&#xff0c;1y 2x4、设置颜色相关5、光标显隐6、关闭控制台思考 移动方块 控制台输入 //如果ReadKey(true)不会把输入的内容显示再控制台上 char c Console.ReadKey(true).KeyChar;1、清空 ​ Cons…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(二)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 3 - 4节&#xff09; P3《开发准备-了解ArkTS》 鸿蒙开发主要是用来开发移动端应用的。 以前我们开发移动端应用的代码&#xff…

Linux 认识与学习Bash——2

1 read 从键盘读取变量的值 read 后面不带变量&#xff0c;那么默认会给REPLY变量赋值 #!/bin/bash echo -n "请输入你的名字&#xff1a;" read name echo "欢迎您 $name" echo "----------------"echo -n "请输入你的名字2&#xff1a;&q…

[MoeCTF-2022]Sqlmap_boy

title:[MoeCTF 2022]Sqlmap_boy 查看网页源代码&#xff0c;得到提示 <!-- $sql select username,password from users where username".$username." && password".$password.";; --> 用万能密码绕过&#xff0c;用’"闭合 爆数据库…

HOOPS Commuicator:基于Web的交互式2D/3D图形轻量化引擎

在当前数字化时代&#xff0c;Web基础的3D应用程序正在成为行业标准&#xff0c;尤其是在工程和制造领域。Tech Soft 3D公司旗下的HOOPS Communicator正是针对这一需求设计的高级解决方案&#xff0c;提供了一套全面的工具&#xff0c;旨在帮助开发者构建复杂的3D工程应用程序。…

Springboot+Vue项目-基于Java+MySQL的图书馆管理系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

【信号处理】基于CNN的心电(ECG)信号分类典型方法实现(tensorflow)

关于 本实验使用1维卷积神经网络实现心电信号的5分类。由于数据类别不均衡&#xff0c;这里使用典型的上采样方法&#xff0c;实现数据类别的均衡化处理。 工具 方法实现 数据加载 Read the CSV file datasets: NORMAL_LABEL0 , ABNORMAL_LABEL1,2,3,4,5 ptbdb_abnormalpd.…

【行为型模式】解释器模式

一、解释器模式概述 解释器模式定义&#xff1a;给分析对象定义一个语言&#xff0c;并定义该语言的文法表示&#xff0c;再设计一个解析器来解释语言中的句子。也就是说&#xff0c;用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口&#xff0c;该接口…

代码随想录第三十天|无重叠区间| 划分字母区间| 合并区间

今天三道都是重叠区间问题&#xff0c;重叠区间问题第一步就是先对数组进行排序&#xff0c;才能进行后续操作。 无重叠区间 这一题和昨天的最少多少支箭射爆气球的解法是相同的&#xff0c;判断相邻区间是否重叠&#xff0c;若两个区间重叠了则找出重叠区间最小右边界&#…

怎样用PHP语言实现远程控制三路开关

怎样用PHP语言实现远程控制三路开关呢&#xff1f; 本文描述了使用PHP语言调用HTTP接口&#xff0c;实现控制三路开关&#xff0c;三路开关可控制三路照明、排风扇等电器。 可选用产品&#xff1a;可根据实际场景需求&#xff0c;选择对应的规格 序号设备名称厂商1智能WiFi墙…

C++:模板(初级)

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《C&#xff1a;模板&#xff08;初级&#xff09;》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 如果本篇文章对你有帮助&#xff0c;还请各位点点赞…

Docker容器搭建Hadoop集群(hadoop-3.1.3)

Docker容器环境下搭建Hadoop集群&#xff08;完全分布式&#xff09; hadoop版本为hadoop-3.1.3 &#xff08;1&#xff09;安装额外的速度较快的镜像库 yum install -y epel-release &#xff08;2&#xff09;安装同步工具&#xff0c;方便在多台服务器上进行文件的传输 …