【多线程初阶】线程状态 线程安全

article/2025/7/18 17:32:29

文章目录

  • 1.线程状态
    • 线程的状态及状态转移
  • 2.多线程带来的风险 - 线程安全(重点)
    • 线程安全问题产生的原因
    • 如何解决线程安全问题

1.线程状态

EE的第一篇总览中有提到过
进程的状态
1.就绪
2.阻塞
在这里插入图片描述

这都是从操作系统的视角看待的
Java线程也是对操作系统线程的封装,针对状态这里,Java也进行了重新封装,来进行表示

线程的状态及状态转移

在这里插入图片描述

  • NEW : 安排了工作,还未开始行动 -->new 了 Thread 对象,还没 start
    在这里插入图片描述

  • TERMINATED : 工作完成了 -->内核中的线程已经结束了,但是 Thread 对象还在
    在这里插入图片描述

  • RUNNABLE : 可工作的,又可以分成正在工作中或即将开始工作的
    就绪: 1).线程正在CPU上执行 2).线程随时可以去CPU上执行
    比如,前面所举的例子,约A开会,A没有出差,随时可以一起开会

在这里插入图片描述

  • TIMED_WAITING : 这几个都表示排队等着其他事情

①.sleep 状态由RUNNABLE 转变为 TIMED_WAITING
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

②.另外,join(时间)也会进入到TIMED_WAITING状态

指定时间的阻塞,线程阻塞(不参与CPU调度,不继续执行了),阻塞的时间是有上限的

在这里插入图片描述

  • WAITING : 这几个都表示排队等着其他事情

与TIMED_WAITING 的区别,WAITING 会死等,没有超时时间的阻塞等待

在这里插入图片描述
在这里插入图片描述

  • BLOCKED : 这几个都表示排队等着其他事情

也是一种阻塞,比较特殊,由于 锁 导致的阻塞

这个线程状态等我们介绍到线程安全问题 涉及到死锁再进行演示

多线程的程序中,理解线程状态,是帮助我们调试程序的关键

比如,发现代码中某个逻辑,好像卡死了(明明调用了,却没有执行/没有执行完)
1.jconsole / 其他工具,查看当前的进程中的所有线程,找到你对应逻辑的线程是谁
2.看线程的状态是啥
看到 TIMED_WAITING / WAITING ,怀疑是不是代码中某个方法产生阻塞,没有被及时唤醒
看到 BLOCKED ,怀疑是不是代码中出现死锁
看到 RUNNABLE ,线程本身没问题,考虑逻辑上某些条件没有预期触发之类的
3.再看看线程具体的调用栈(尤其是 阻塞的状态,线程的代码阻塞在哪一行了…)

2.多线程带来的风险 - 线程安全(重点)

想给出一个线程安全的确切定义是复杂的,但我们可以这样认为:如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的

如果不理解线程安全问题,是很难保证写出正确的多线程代码的

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
再回到我们观察到的现象,多次执行的结果都不一样并且没有达到预期结果

这样的代码很明显就是有BUG
实际执行效果和预期效果不符合,就叫bug
这样的问题,多线程并发执行引起的问题
如果把两个线程,变成串行执行(一个结束,再执行另一个)

我们将代码写成纯串行执行,观察现象
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
CPU内部包含寄存器这样的模块,寄存器也能存一些数据
在这里插入图片描述
我们使用时间轴(先执行的画上面,后执行的画下面)来模拟几个随机调度的顺序,我们只画几种情况,肯定不止这些,因为调度次序存在无数种可能

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

第一种情况的具体分析

在这里插入图片描述
第三种情况的具体分析

在这里插入图片描述
其他的情况就不一一进行分析了
通过上述讨论,不难发现,如果两个线程load时出现的数据都是0,那么意味着一定会少加一次,如果一个load到0另一个load到1,结果就是正确的,也就是说一个线程load需要再另一个线程的save之后才是正确的,所以我们上述的6种随机调度情况只有前两种是正确的

那么上述代码运行出来一定是 >=5w的吗?是否有可能<5w?
是有可能的,只不过概率很小
可以再用随机调度的情况分析一下,是否存在这种情况
在这里插入图片描述

是有可能的,只不过概率要小很多

在这里插入图片描述
在这里插入图片描述

50次和5000次甚至5w次,线程执行的时间长短是不同的
如果是循环50次,很可能在t2.start开始之前,t1 就算完了等后续t2再执行,虽然代码写的是并行,但变成纯串行了

线程安全问题产生的原因

在这里插入图片描述
本篇文章先讨论前三种原因

  • 1.[根本原因] 操作系统对于线程的调度是随机的,抢占式执行
  • .多个线程同时对同一变量进行修改
    在这里插入图片描述

如果是一个线程修改一个变量 -->没问题
如果是多个线程,不是同时修改同一个变量 -->没问题
如果多个线程修改不同变量 -->没问题
如果多个线程读取同一变量 -->没问题
这些都不会出现中间结果相互覆盖的情况
其中修改操作->写,取值操作->读

  • 3.修改操作,不是原子的

原子性,在数据库-事务的学习中,有提到
事务具有1.原子性 2.一致性 3. 持久性 4.隔离性
其中这个原子性,如果是修改操作.只是对应到一个CPU指令,就可以认为是原子的 ,CPU不会出现"一条指令执行一半"的情况,但是count++ 这行代码对应三条CPU指令,就不是原子的

像是++,–,+=,-=都不是原子的,像 = 赋值操作在Java就是原子的

  • 4.内存可见性问题,引起的线程不安全
  • 5.指令重排序引起的线程不安全

最后两个问题,我们后续再讨论~~

如何解决线程安全问题

  • 1.[根本问题]操作系统对于线程的调度是随机的,抢占式执行

这是操作系统的底层设定,我们左右不了

  • 2.多个线程同时对同一变量进行修改

这个和代码的结构相关,调整代码结构,规避一些线程不安全的代码,但是这样的方案不够通用,有些情况下,需求上就是需要多线程修改同一变量,比如超买/超卖的问题:某个商品,库存100件,能否创建101个订单?

  • 3.修改操作,不是原子的

Java中解决线程安全问题的最主要方案:加锁

计算机中的锁,和生活中的锁,是同样的概念,互斥/排他的
把锁"锁上" 称为 “加锁”
把锁"解开" 称为 “解锁”
一旦把锁加上了,其他人要想加锁,必须要阻塞等待

就可以使用锁,把刚才不是原子操作的 count++ 包裹起来,在count++ 之前,先加锁,然后进行 count++,计算完毕后,在解锁,也就是在执行三条CPU指令过程中,其他线程就没法插队了

加锁操作,不是禁止这个线程被调度走,而是禁止其他线程重新加这个锁,避免其他线程的操作在当前线程执行过程中,插队

加锁/解锁 本身是 操作系统提供的API,很多编程语言都对于这样的API进行了封装,大多数的封装风格,都是采取lock()加锁,unlock()解锁 这两个函数

在Java中使用 synchronized 这样的关键字,搭配代码块,来实现类似的效果

  • 进入 synchronized 修饰的代码块,相当于加锁
  • 退出 synchronized 修饰的代码块,相当于解锁

http://www.hkcw.cn/article/ORQasdKxks.shtml

相关文章

Python 序列的修改、散列和切 片(Vector类第4版:散列和快速等值 测试)

Vector类第4版&#xff1a;散列和快速等值测试 我们要再次实现__hash__ 方法。加上现有的__eq__ 方法&#xff0c;这会把 Vector 实例变成可散列的对象。 示例 9-8 中的__hash__ 方法简单地计算 hash(self.x) ^ hash(self.y)。这一次&#xff0c;我们要使用^&#xff08;异或…

ai姿势项目

链接:https://pan.baidu.com/s/1dGSt7wEk8w6O7zlgme3CUQ?pwd=x60y 提取码:x60y --来自百度网盘超级会员V2的分享 配置环境 conda create -n 环境名称 python=3.8conda activate 环境名称 如果你运行程序的话会报错 ModuleNotFoundError: No module named mediapipe 进…

LoRA:高效微调预训练模型的利器

LoRA(Low-Rank Adaptation) 的思想&#xff1a;冻结预训练模型权重&#xff0c;将可训练的低秩分解矩阵注入到Transformer架构的每一层(也可单独配置某一层)中&#xff0c; 从而大大减少在下游任务的可训练参数量。 核心原理 对于预训练权重矩阵 &#xff0c;LoRA限制了其更新…

越界检测算法AI智能分析网关V4打造多场景化的应用解决方案

一、方案概述 随着社会发展&#xff0c;传统安防系统在复杂环境下暴露出误报率高、响应慢等短板。AI智能分析网关V4依托先进算法与强大算力&#xff0c;实现周界区域精准监测与智能分析&#xff0c;显著提升入侵防范效能。本方案通过部署该网关及其越界检测功能&#xff0c;为…

使用SkiaSharp打造专业级12导联心电图查看器:性能与美观兼具的可视化实践

前言 欢迎关注dotnet研习社&#xff0c;今天我们研究的Google Skia图形库的.NET绑定SkiaSharp图形库。 在医疗软件开发领域&#xff0c;心电图(ECG)数据的可视化是一个既有挑战性又极其重要的任务。作为开发者&#xff0c;我们需要创建既专业又直观的界面来展示复杂的生物医学…

24位高精度数据采集卡NET8860音频振动信号采集监测满足自动化测试应用现场的多样化需求

NET8860 高分辨率数据采集卡技术解析 阿尔泰科技的NET8860是一款高性能数据采集卡&#xff0c;具备8路同步模拟输入通道和24bit分辨率&#xff0c;适用于高精度信号采集场景。其输入量程覆盖10V、5V、2V、1V&#xff0c;采样速率高达256KS/s&#xff0c;能够满足多种工业与科研…

2025年05月30日Github流行趋势

项目名称&#xff1a;agenticSeek 项目地址url&#xff1a;https://github.com/Fosowl/agenticSeek项目语言&#xff1a;Python历史star数&#xff1a;13040今日star数&#xff1a;1864项目维护者&#xff1a;Fosowl, steveh8758, klimentij, ganeshnikhil, apps/copilot-pull-…

PCB设计实践(三十一)PCB设计中机械孔的合理设计与应用指南

一、机械孔的基本概念与分类 机械孔是PCB设计中用于实现机械固定、结构支撑、散热及电气连接的关键结构元件&#xff0c;其分类基于功能特性、制造工艺和应用场景的差异&#xff0c;主要分为以下几类&#xff1a; 1. 金属化机械孔 通过电镀工艺在孔内壁形成导电层&#xff0c;…

TC/BC/OC P2P/E2E有啥区别?-PTP协议基础概念介绍

前言 时间同步网络中的每个节点&#xff0c;都被称为时钟&#xff0c;PTP协议定义了三种基本时钟节点。本文将介绍这三种类型的时钟&#xff0c;以及gPTP在同步机制上与其他机制的区别 本系列文章将由浅入深的带你了解gPTP&#xff0c;欢迎关注 时钟类型 在PTP中我们将各节…

五.MySQL表的约束

1.not null空属性 和 default缺省值 两个值&#xff1a;null&#xff08;默认的&#xff09;和not null(不为空) 元素可以分为两类 1.not null 不能为空的&#xff0c;这种没有默认default 要手动设定&#xff0c;我们必须插入数据而且不能为NULL。但我们插入数据有两种方式 1.…

4.Haproxy搭建Web群集

一.案例分析 1.案例概述 Haproxy是目前比较流行的一种群集调度工具&#xff0c;同类群集调度工具有很多&#xff0c;包括LVS、Nginx&#xff0c;LVS性能最好&#xff0c;但是搭建相对复杂&#xff1b;Nginx的upstream模块支持群集功能&#xff0c;但是对群集节点健康检查功能…

NewsNow:免费好用的实时新闻聚合平台,让信息获取更优雅(深度解析、部署攻略)

名人说&#xff1a;博观而约取&#xff0c;厚积而薄发。——苏轼《稼说送张琥》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、NewsNow项目概览1. 项目核心亮点2. 技术架构特点 二、核心功能深度解析1. 智能新…

论文阅读笔记——FLOW MATCHING FOR GENERATIVE MODELING

Flow Matching 论文 扩散模型&#xff1a;根据中心极限定理&#xff0c;对原始图像不断加高斯噪声&#xff0c;最终将原始信号破坏为近似的标准正态分布。这其中每一步都构造为条件高斯分布&#xff0c;形成离散的马尔科夫链。再通过逐步去噪得到原始图像。 Flow matching 采取…

【leetcode】02.07. 链表相交

链表相交 题目代码1. 计算两个链表的长度2. 双指针 题目 02.07. 链表相交 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 代码 …

文字转图片的字符画生成工具

软件介绍 今天要介绍的这款软件可以将文字转换成图片的排列形式&#xff0c;非常适合需要将文字图形化的场景&#xff0c;建议有需要的朋友收藏。 软件名称与用途 这款软件名为《字符画大师》&#xff0c;是一款在网吧等场所非常流行的聊天辅助工具&#xff0c;其主要功能就…

Bitlocker密钥提取之SYSTEM劫持

该漏洞编号CVE-2024-20666&#xff0c;本文实现复现过程&#xff0c;Windows系统版本如下 简介 从Windows10&#xff08;th1&#xff09;开始&#xff0c;微软在winload模块中&#xff0c;增加了systemdatadevice字段值的获取&#xff0c;该字段值存储在BCD引导配置文件中。当…

明场检测与暗场检测的原理

知识星球里的学员问&#xff1a;明场检测与暗场检测原理上有什么区别&#xff1f; 如上图&#xff0c; 明场检测&#xff08;Bright-field Inspection&#xff09; 工作原理&#xff1a; 光线从近乎垂直照射到样品表面。 如果表面平整、无缺陷&#xff0c;光线会直接反射回镜…

STL解析——vector的使用及模拟实现

目录 1.使用篇 1.1默认成员函数 1.2其他常用接口 2.模拟实现 2.1源码逻辑参考 2.2基本函数实现 2.3增 2.4删 2.5迭代器失效 2.6拷贝构造级其他接口 2.7赋值运算符重载(现代写法) 2.8深层次拷贝优化 3.整体代码 在C中vector算正式STL容器&#xff0c;功能可以类比于…

day2实训

实训任务1 FTPASS wireshark打开 实训任务2 数据包中的线索 解码的图片 实训任务3 被嗅探的流量 过滤http&#xff0c;追踪post的http流 实训任务6 小明的保险箱 winhex打开

Window10+ 安装 go环境

一、 下载 golang 源码&#xff1a; 去官网下载&#xff1a; https://go.dev/dl/ &#xff0c;当前时间&#xff08;2025-05&#xff09;最新版本如下: 二、 首先在指定的磁盘下创建几个文件夹 比如在 E盘创建 software 文件夹 E:\SoftWare,然后在创建如下几个文件夹 E:\S…