多线程(三):Thread 类的基本属性
上一个篇章浅浅了解了一下 线程的概念,进程与线程的区别,如何实现多线程编程。
而且上一章提到一个重要的面试点: start 方法和 run 方法的区别。
start 方法是从系统那里创建一个新的线程,这个线程会自动调用内部的run 方法;
run 方法是一个线程的执行入口,所有的实现逻辑都写在该方法里。
从概念上来说,这两个方法是属于线程的属性。我们接着这个线程属性继续来认识线程。
线程属性
就像我们之前写的代码:

我们如何让某个线程中断呢?
这里的中断意味着:让线程停下来,线程的终止。
本质上来说让线程终止的办法只有一种,让线程的入口方法 执行完毕。无论是是 return 、抛出异常还是别的方法都是执行完毕。
这里就需要提到 给线程设定一个结束标志。
给线程设定一个结束标志
来看下面的这段代码:

我们可以选择这种方式来控制循环,不让他写的那么死。

但这仍是我们自己设置的变量,而不属于线程的属性,线程中也有个方法:interru方法
interru方法
我们来看看这一段代码:
我们这里就用到了几个线程的属性,
Thread.currentThread()、isInterrupted()、t.interrupt()
上述的e.printStackTrace() 就是打印出异常信息。
我们来看看结果:

我们发现,在main线程睡眠了 3s 之后并没有打印完异常就结束,而是继续线程 t 的运行。
这是为什么呢?
这就需要来聊聊 interrupt 方法的作用了:
- 将标识符设置为 true
- 如果该线程正在阻塞状态中(例如:sleep,后面还有其他方法也会使线程阻塞),会直接被interrupt 方法唤醒,此时通过抛出异常就会让 sleep 立即结束。
按照 interrupt 方法的作用,此时应该结束了啊,t 线程这么还会继续呢?
这里有个非常重要的点;
当 sleep 被唤醒以后,会自动将 isInterrupted 设置为 false,也就是说将异常标志位清空了(true -> false);
sleep 为什么要清空异常标志位呢?
目的是为了让这个线程能够对于线程什么时候结束有一个更精准的控制。
当前的 interrpt 方法是告诉线程你该结束了,至于什么时候结束,都是由代码灵活控制的。
interrpt 方法 是个通知而不是命令。
等待线程 -- join 方法
线程与线程之间的的并发执行的,线程间的调度是无序的,我们无法判断两个线程之间谁先结束谁后结束。
例如:

但是我们可以通过 join 方法进行控制,例如:

在t 执行 join 方法时,如果 t 线程尚未结束,那么main线程就会进入 Blocking (阻塞状态),因为t.join 在 main线程中执行。
main 线程代码走到这一行 就不参与 cpu 的执行调度了。
如果这个有多个线程并发执行, 那么 只是main 线程不参与线程的调度,其余的线程任然是抢占执行的。
我们使用的 join 是无参的版本,我们还存在另一个带参的版本。
这个带参的版本,参数作为等待的最大时间,超过了这个最大时间,t 线程还没有结束,那么main 线程 就会被唤醒,不再是Blocking 状态 就会继续执行。
而上面不带参的版本,就是死等,等不到 t 线程结束,mian 线程就不会开始。
既然上面都提到了线程状态,那么就简单理解一下线程状态。
线程状态
Java中线程的状态分为6种:
1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
2. 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
3. 阻塞(BLOCKED):表示线程阻塞于锁。
4. 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
5. 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
6. 终止(TERMINATED):表示该线程已经执行完毕。

我们简单理解就是一条主线,三条支线。
我们就简单了解一下就好,后面还会再聊到。
简单了解线程安全
对于多线程编程雀氏提供了很多便利,我们可以再同一时间完成多个任务,相比于多进程编程多线程还降低了 cpu 资源的占用。
这几章都提到了,多线程之间的线程调度是抢占式执行的,所以在此基础之上会产生很多的线程安全问题。
本章就稍稍介绍认识一下线程安全的问题就行。
本章以一个不安全的例子来认识
例如:我们设置一个 count ,两个线程各执行 5 w 次自增运算。
代码如下:
class Count {private int count = 0;public void add() {count++;}public int get() {return count;}
}
public class demo10 {public static void main(String[] args) throws InterruptedException {Count count = new Count();Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {count.add();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {count.add();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count.get());}
}
运行一次看看结果:

再来试试看:
再来一次:

从结果上来看它是一个随机数。
至于为什么会产生一个随机数,我们需要了解在这执行的内部发生了什么事情:
对于这个 count++ 这个操作,本质上是由 cpu 上三个指令构成的:
- load : 从内存中将数据读取到 cpu 寄存器中
- add :在 cpu 中的值进行 + 1 运算
- save : 把寄存器中的值写入到内存中
由于是抢占式执行的,那么就会产生如下等问题:

这个 3 的执行顺序就变成不确定的了,产生多种排列组合结果。
只有 25 亿分之 1 的可能得到 10w 这个数字,也有可能会产生结果小于 5w 具体的可以自己排列组合看看。
对于 t1 和 t2 这两个线程可能式运行在同一个 cpu 核心上执行,也有可能在不同的 cpu 核心上执行。
归根结底,线程安全问题,全是因为线程之间的无序调度,导致了执行顺序不确定,结果不确定。
相关文章:
多线程(三):Thread 类的基本属性
上一个篇章浅浅了解了一下 线程的概念,进程与线程的区别,如何实现多线程编程。 而且上一章提到一个重要的面试点: start 方法和 run 方法的区别。 start 方法是从系统那里创建一个新的线程,这个线程会自动调用内部的run 方法&…...
蓝桥杯嵌入式第六课--串口收发
前言串口作为一个考试中考察频率较高的考点,其套路比较固定,因此值得我们仔细把握。本节课主要着眼于快速配置实现 串口收发与串口的中断。CubeMX配置选择串口2配置异步收发模式基本参数设置(波特率、校验位等等)开启串口收发中断…...
蓝桥杯冲刺 - Lastweek - 你离省一仅剩一步之遥!!!(掌握【DP】冲刺国赛)
文章目录💬前言🎯week3🌲day10-1背包完全背包多重背包多重背包 II分组背包🌲day2数字三角形 - 线性DP1015. 摘花生 - 数字三角形🌲day3最长上升子序列 - 线性DP1017. 怪盗基德的滑翔翼 - LIS1014.登山 - LIS最长公共子…...
C++ map与set的学习
1. 关联式容器在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、forward_list(C11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。关联式容器也…...
【C语言初阶】函数
文章目录💐专栏导读💐文章导读🌷函数是什么?🌷函数的分类🌺库函数🌺自定义函数🌷函数的参数🌷函数的调用🌷函数的嵌套调用和链式访问🌺嵌套调用&a…...
CentOS 7安装redis6.2.6(包括服务开机自启和开放端口)
CentOS 7安装redis6.2.61. 官网下载redis文件2. 校验安装依赖2.1 安装系统默认版本gcc2.2 升级gcc版本3. 解压编译安装4. 修改配置redis.conf4.2 设置密码4.3 绑定ip(可选)5. 启动redis服务并测试5.2 测试安装是否成功5.3 redis开机自启配置6.开放防火墙…...
基于注解的自动装配~
Autowired:实现自动装配功能的注解 Autowired注解能够标识的位置: 标识在成员变量上,此时不需要设置成员变量的set方法标识在成员变量对应的set方法上标识在为当前成员变量赋值的有参构造上使用注解进行自动装配,只要在其成员变量…...
【深度学习】【分布式训练】Collective通信操作及Pytorch示例
相关博客 【深度学习】【分布式训练】Collective通信操作及Pytorch示例 【自然语言处理】【大模型】大语言模型BLOOM推理工具测试 【自然语言处理】【大模型】GLM-130B:一个开源双语预训练语言模型 【自然语言处理】【大模型】用于大型Transformer的8-bit矩阵乘法介…...
Spring常用注解说明
目录 1.常用注解 2.特别说明 3.xml及注解方式 1.常用注解 (1) SpringBootApplication (2) ControllerRestControllerRequestMappingRequestParamPathVariableGetMappingPostMappingPutMappingDeleteMappingResponseBodyRequestBodyCrossOrigin (3) ConfigurationBeanServ…...
13-C++面向对象(纯虚函数(抽象类)、多继承、多继承-虚函数、菱形继承、虚继承、静态成员)
虚析构函数 存在父类指针指向子类对象的情况,应该将析构函数声明为虚函数(虚析构函数) 纯虚函数 纯虚函数:没有函数体且初始化为0的虚函数,用来定义接口规范 抽象类: 含有纯虚函数的类,不可以实…...
Android DataBinding 自定义View实现数据双向绑定
看不懂的可以先看看单向数据绑定:Android DataBinding数据变化时自动更新界面_皮皮高的博客-CSDN博客 然后再确定已经启动了dataBinding的情况下,按下面的顺序来: 首先创建一个自定义View: import android.content.Context imp…...
网络安全中的渗透测试主要那几个方面
渗透测试中主要有软件测试和渗透测试。 1、测试对象不同 软件测试:主要测试的是程序、数据、文档。 渗透测试:对象主要为网络设备、主机操作系统、数据库系统和应用系统。 2、测试内容不同 软件测试:主要工作内容是验证和确认,发…...
Cursor:GPT-4 驱动的强大代码编辑器
Cursor (https://www.cursor.so/)是 GPT-4 驱动的一款强大代码编辑器,可以辅助程序员进行日常的编码。下面通过一个实际的例子来展示 Cursor 如何帮助你编程。这个例子做的事情是网页抓取。抓取的目标是百度首页上的百度热搜,如下…...
C/C++中for语句循环用法及练习
目录 语法 下面是 for 循环的控制流: 实例 基于范围的for循环(C11) 随堂笔记! C语言训练-计算1~N之间所有奇数之和 题目描述 输入格式 输出格式 样例输入 样例输出 环形方阵 干货直达 for 循环允许您编写一个执行特定次数的循环的重复控制结构。…...
AnimatorOverrideController说明
unity-AnimatorOverrideControllerhttps://docs.unity.cn/cn/current/ScriptReference/AnimatorOverrideController.html 用于控制动画器重写控制器的接口。 动画器重写控制器的用途是重写某个控制器的动画剪辑,从而为给定化身定制动画。 在运行时基于相同的 Anim…...
1.4、第三阶段 MySQL数据库
root数据库技术 一、数据库理论 1 什么是数据库技术 数据库技术主要研究如何组织、存储数据,并如何高效地提取和处理数据。 2 什么是SQL SQL(Structured Query Language)结构化查询语言 SQL是操作数据库的命令集,也是功能齐全的…...
LeetCode:202. 快乐数
🍎道阻且长,行则将至。🍓 🌻算法,不如说它是一种思考方式🍀算法专栏: 👉🏻123 一、🌱202. 快乐数 题目描述:编写一个算法来判断一个数 n 是不是快…...
Android 14 新功能之 HighLights:快速实现文本高亮~
日常开发中可能会遇到给 TextView 的全部或部分文本增加高亮效果的需求,以前可能是通过 Spannable 或者 Html 标签实现。 升级 Android 14 后就不用这么迂回了,因其首次引入直接设置高亮的 API:HighLights。需要留意的是 HighLights API 和 …...
[渗透教程]-004-嗅探工具-Nmap
文章目录 Nmap介绍基本操作进阶操作Nmap介绍 nmap是一个网络扫描和主机检测工具,它可以帮助用户识别网络上的设备和服务。获取主机正在运行哪些服务,nmap支持多种扫描,UDP,TCP connect(),TCP SYN(半开扫描) ftp代理,反向标志,ICMP,FIN,ACK扫描,ftp代理,反向标志,ICMP. 可以用于…...
大数据技术之Hive SQL题库-初级
第一章环境准备1.1 建表语句hive>-- 创建学生表 DROP TABLE IF EXISTS student; create table if not exists student_info(stu_id string COMMENT 学生id,stu_name string COMMENT 学生姓名,birthday string COMMENT 出生日期,sex string COMMENT 性别 ) row format delim…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
实战三:开发网页端界面完成黑白视频转为彩色视频
一、需求描述 设计一个简单的视频上色应用,用户可以通过网页界面上传黑白视频,系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观,不需要了解技术细节。 效果图 二、实现思路 总体思路: 用户通过Gradio界面上…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...
机器学习的数学基础:线性模型
线性模型 线性模型的基本形式为: f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回归问题 利用最小二乘法,得到 ω \boldsymbol{\omega} ω和 b b b的参数估计$ \boldsymbol{\hat{\omega}}…...
数据库正常,但后端收不到数据原因及解决
从代码和日志来看,后端SQL查询确实返回了数据,但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离,并且ai辅助开发的时候,很容易出现前后端变量名不一致情况,还不报错,只是单…...
