线程安全

原子性(Atomicity)、可见性(Visibility)、有序性(Ordering) 是保证线程安全的三大核心要素 —— 线程安全问题的本质,几乎都是这三个特性中的一个或多个被破坏导致的。

  • 操作不会被 “中途打断”(原子性);
  • 操作结果能被其他线程 “及时看见”(可见性);
  • 操作顺序符合 “语义逻辑”(有序性)。

可见性:

可见性问题指:一个线程对共享变量的修改,其他线程可能无法立即看到,甚至永远看不到

为什么影响线程安全?
若可见性被破坏,线程会基于 “旧值” 做决策或修改,导致逻辑错误。

现代 CPU 为提升效率,引入了多级缓存(L1、L2、L3),线程的 “工作内存” 本质是 CPU 缓存的抽象。当线程修改变量时:

  • 步骤 1:修改 CPU 缓存中的副本(工作内存)。
  • 步骤 2:CPU 会在 “合适的时机”(而非立即)将缓存中的新值刷新到主内存(如缓存满了、发生缓存一致性协议触发时)。

这就导致:若线程 A 刚修改了变量但未刷新到主内存,线程 B 从主内存读取的仍是旧值,出现可见性问题。

可见性问题的产生

当线程 A 修改了共享变量 A 时,会先更新自己的工作内存,再异步刷新到主内存(这个过程有延迟)。若此时线程 B 读取变量 A,可能直接从自己的工作内存中获取未被更新的老值(因为线程 A 的修改还未同步到主内存,或线程 B 未从主内存重新加载),导致两个线程看到的变量值不一致。

// 共享变量
private static boolean flag = false;// 线程1:修改flag
new Thread(() -> {flag = true; // 修改工作内存中的flag,尚未同步到主内存System.out.println("线程1已修改flag为true");
}).start();// 线程2:读取flag
new Thread(() -> {while (!flag) { // 可能一直读取自己工作内存中的老值(false),陷入死循环// 等待flag变为true}System.out.println("线程2检测到flag为true");
}).start();

线程 2 可能永远看不到线程 1 对 flag 的修改,因为 flag 的更新未及时同步到主内存,或线程 2 未重新从主内存加载。

volatile解决:

volatile 保证可见性的核心逻辑是:强制线程对变量的读写操作直接与主内存交互,跳过工作内存(CPU 缓存)的缓存优化,具体通过以下两步实现:

  1. 写操作时:立即刷新到主内存,并使其他线程的缓存失效
    当线程修改一个 volatile 变量时,JVM 会触发两个动作:

    • 强制将工作内存中该变量的新值立即刷新到主内存(不等待 CPU 缓存的 “合适时机”)。
    • 通过 CPU 的缓存一致性协议(如 MESI 协议),通知其他线程中该变量的缓存副本失效(其他线程再读取时必须从主内存重新加载)。

    类比:volatile 变量的写操作相当于 “写完立即把笔记本内容抄回公共白板,并擦掉其他人笔记本上的旧内容”。

  2. 读操作时:必须从主内存重新加载
    当线程读取 volatile 变量时,JVM 会强制线程放弃工作内存中的缓存副本,直接从主内存加载最新值。

    类比:volatile 变量的读操作相当于 “每次看内容前,都先扔掉自己的笔记本,重新从公共白板抄最新内容”。

private static volatile boolean flag = false; // 用volatile修饰// 线程1修改后,会立即刷新到主内存,并使线程2的缓存失效
// 线程2读取时,会从主内存重新加载,感知到flag的最新值

synchronized解决

核心机制是加锁和解锁时的内存同步操作

  1. 加锁时(进入同步块)
    线程会清空自己的工作内存,并从主内存重新加载共享变量的最新值到工作内存。
    (类比:线程进入同步块前,先把自己的 “笔记本” 清空,重新从 “公共白板” 抄最新内容。)

  2. 解锁时(退出同步块)
    线程会将工作内存中修改后的共享变量值强制刷新到主内存
    (类比:线程退出同步块时,必须把 “笔记本” 的修改立即抄回 “公共白板”。)

  3. happens-before 原则
    对同一个锁,解锁操作 happens-before 后续的加锁操作。即:前一个线程解锁时刷新到主内存的变量值,后一个线程加锁时必然能从主内存读到这个最新值。

// 共享变量(无volatile)
private static boolean flag = false;public static void main(String[] args) {// 线程1:修改flagnew Thread(() -> {synchronized (Test.class) { // 加锁:从主内存加载flag(初始false)flag = true; // 修改工作内存中的flag} // 解锁:将flag=true刷新到主内存}).start();// 线程2:读取flagnew Thread(() -> {while (true) {synchronized (Test.class) { // 加锁:从主内存加载flag的最新值if (flag) {System.out.println("线程2读取到flag=true");break;}} // 解锁:无修改,不影响}}).start();
}
  • 线程 1 解锁时,flag=true 被强制刷新到主内存。
  • 线程 2 每次加锁时,都会从主内存重新加载 flag,因此必然能感知到 flag 的修改,最终退出循环。

有序性

有序性指程序执行顺序符合代码的 “语义逻辑顺序”,避免编译器 / CPU 的指令重排序破坏线程间的依赖关系。

为什么影响线程安全?
重排序可能打破线程间的 “操作先后依赖”,导致基于顺序的逻辑判断失效。

// 共享变量
private static int a = 0;
private static boolean flag = false;// 线程1:先初始化a,再标记flag
new Thread(() -> {a = 1;      // 操作1:初始化aflag = true; // 操作2:标记a已初始化
}).start();// 线程2:基于flag判断a是否可用
new Thread(() -> {if (flag) { // 若flag=true,认为a已初始化System.out.println(a); // 可能输出0(因重排序)}
}).start();

若线程 1 的操作 1 和操作 2 被重排序(先执行 flag=true,再执行 a=1),线程 2 会在 a 未初始化时读取,输出 0(不符合预期),破坏线程安全。

volatile解决有序性:

volatile 通过在变量的读写操作前后插入内存屏障(Memory Barrier) 来禁止特定类型的重排序,从而保证有序性。内存屏障是一种特殊的指令,它会阻止编译器和 CPU 对屏障两侧的指令进行重排序。

volatile 内存屏障的具体规则

操作类型内存屏障插入位置作用
写操作(v = x)写操作前插入 StoreStore 屏障禁止当前写操作与之前的其他写操作重排序(确保之前的写操作先于当前写操作执行)。
写操作后插入 StoreLoad 屏障禁止当前写操作与之后的读 / 写操作重排序(确保当前写操作完成后,再执行后续操作)。
读操作(x = v)读操作前插入 LoadLoad 屏障禁止当前读操作与之前的其他读操作重排序(确保之前的读操作先于当前读操作执行)。
读操作后插入 LoadStore 屏障禁止当前读操作与之后的写操作重排序(确保当前读操作完成后,再执行后续写操作)。

这些屏障的核心作用是 “隔离屏障两侧的指令”,确保 volatile 变量的读写操作不会与其他指令 “交叉执行”。

synchronized解决有序性: 

synchronized 通过 “happens-before 原则” 和 “同步块的边界约束” 保证有序性。其核心逻辑是:同步块内的操作会被视为一个 “不可分割的整体”,不会与同步块外的操作重排序,且后续线程进入同步块时,能看到之前同步块内的所有操作结果。

  1. 同步块内的操作不会被重排序到块外
    JMM 规定:编译器和 CPU 不得将同步块内的指令重排序到同步块外部(无论是进入块前还是退出块后)。例如:

    synchronized (lock) { // 加锁a = 1;    // 同步块内操作1flag = true; // 同步块内操作2
    } // 解锁

    编译器和 CPU 不能将 a=1 或 flag=true 重排序到 synchronized 块外部,确保同步块内的操作顺序严格按代码执行。

  2. happens-before 关系保证跨线程可见性与顺序性
    JMM 的 happens-before 原则规定:对同一个锁的解锁操作 happens-before 后续的加锁操作。即:

    • 线程 A 退出同步块(解锁)时,其在同步块内的所有操作(如 a=1flag=true)都会被刷新到主内存。
    • 线程 B 进入同步块(加锁)时,会从主内存加载所有变量的最新值,因此能看到线程 A 在同步块内的所有操作结果。

    这种关系确保了:线程 A 的操作 “先行发生于” 线程 B 的操作,两者的执行顺序在逻辑上是有序的。

原子性:

原子性指一个操作(或多个操作的组合)要么全部执行,要么全部不执行,不会被其他线程 “打断”,中间状态不会被暴露

典型案例:非原子操作的风险

以 count++ 为例,这是一个看似简单的操作,但在底层会被拆分为 3 个步骤:

  1. 读取:从主内存读取 count 的当前值到线程的工作内存。
  2. 修改:在工作内存中对 count 加 1。
  3. 写入:将修改后的值刷新回主内存。

当两个线程同时执行 count++ 时,可能出现以下交叉执行的情况:

  • 线程 A 读取 count=0 → 线程 B 读取 count=0(此时两者都在步骤 1)。
  • 线程 A 加 1 后 count=1 → 线程 B 加 1 后 count=1(步骤 2)。
  • 线程 A 写入主内存 count=1 → 线程 B 写入主内存 count=1(步骤 3)。

基于锁机制解决:

private int count = 0;// 用synchronized修饰方法,保证count++的原子性
public synchronized void increment() {count++; // 复合操作被synchronized保护,不会被其他线程中断
}

线程进入 synchronized 方法 / 块时必须获取锁,执行完成后释放锁。同一时间只有一个线程能持有锁,确保临界区内的操作不会被其他线程打断。

使用原子类:

CAS 机制Atomic 系列类):通过硬件指令实现无锁原子操作,适合简单场景,性能更优。

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

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

相关文章

Spring Cloud Netflix学习笔记01

文章目录前言一、微服务概述什么是微服务?微服务与微服务架构微服务优缺点优点缺点微服务技术栈有那些?二.SpringCloud入门概述SpringCloud是什么?SpringCloud和SpringBoot的关系Dubbo 和 SpringCloud技术选型总结SpringCloud能干嘛&#xff…

专题:2025母婴行业消费洞察与分龄营养趋势报告|附40 +份报告PDF、交互图表数据汇总下载

原文链接:https://tecdat.cn/?p43654 当95后妈妈拿着计算器对比DHA纯度,当爸爸们为“防红屁屁纸尿裤”货比三家,母婴行业的风向早就变了。从“一把奶粉喂到3岁”到“按月龄定制营养包”,从“进口就好”到“看专利数据下单”&…

redhat6/centos6 配置yum源

由于RHEL6/centos6系统官方早就停止通知维护了,公司的开发服务器有比较老,发现竟然scp都没有装。。。今天配置个本地yum源,安装一下常规软件和开发环境比较简单,直接上代码1.上传一个centos6的iso文件CentOS-6.5-x86_64-bin-DVD1.…

day31 SQLITE

数据库相关函数数据库创建int sqlite3_open( const char *filename, sqlite3 **ppDb);功能:打开数据库,不存在则创建参数:const char *filename 数据库名sqlite3 **ppDb 二级指针,传出ppDb数据库的一级指…

嵌入式-SPI番外之按钮驱动程序的编写-Day15

目录 一、按钮简单操作回忆 二、按钮新操作实现 (1)按钮的点击实现灯亮/灭 ①连接电路 ②初始化板载LED和按钮 ③按钮程序的基本原理(核心仍为0亮/1灭) ④按钮消抖的原理 三、按钮封装的操作-点击,双击&#xf…

星域智链科技:用科技点亮生活,以 AI 拓展无限可能

星域智链科技(东莞市)有限公司简介 星域智链科技(东莞市)有限公司,理念是 让科技便利生活、丰富生活,专注于科技、AI领域。 全场景 GPS 定位器 —— 精准追踪,守护安全,适用于车辆…

国内代理IP在SEO行业中的应用

随着互联网的快速发展,SEO(搜索引擎优化)已经成为了数字营销的重要组成部分。无论是企业还是个人站长,都希望通过SEO提升自己网站的排名和流量。然而,随着竞争的激烈,传统的SEO优化手段已经逐渐显现出局限性…

Linux + arm 内存屏障

ARM 硬件层的屏障指令DMB (Data Memory Barrier):保证在它之前的内存访问(符合给定域/类型)在它之后的内存访问之前对可见性排序。常用域:ish(Inner Shareable),sy(system-wide&…

网络安全中的远程控制活动检测与防御策略

本文还有配套的精品资源,点击获取 简介:远程控制技术在IT领域中用于网络连接和设备操作,但同样被黑客利用进行非法入侵。端口占用情况是识别远程控制活动的关键因素,使用工具如"cports"可以监控这些端口。系统中未知…

UIGestureRecognizer 各个子类以及其作用

在 iOS 里,UIGestureRecognizer 是一个抽象基类,专门用来处理手势事件。它本身不能直接用,必须用它的 子类。这些子类分别对应常见的手势识别器。常见的 UIGestureRecognizer 子类及作用1. UITapGestureRecognizer作用:点击手势&a…

计算机网络 HTTPS 全流程

HTTPS 通信的全流程(特别是 TLS 握手阶段)中使用的三个随机数是保障安全性的核心设计,不能随意减少。每个随机数都承担着至关重要的安全职责。下面详细解释 HTTPS 全流程,并重点分析这三个随机数的作用和必要性:&#…

DL00271-基于YOLOv11的激光雷达LiDAR船舶目标检测含完整数据集

【CSDN推荐】基于YOLOv11的激光雷达(LiDAR)船舶目标检测——含完整数据集!🚢 科研人员必看! 高校老师、学生和研究者们,前沿技术来了!本论文利用YOLOv11模型,结合激光雷达&#xff0…

SQL-leetcode—3374. 首字母大写 II

3374. 首字母大写 II 表:user_content -------------------- | Column Name | Type | -------------------- | content_id | int | | content_text| varchar | -------------------- content_id 是这张表的唯一主键。 每一行包含一个不同的 ID 以及对应的文…

告别笼统的 200 OK:一份给 API 设计者的 HTTP 状态码终极指南

文章目录写在前面问题描述核心结论与建议简要描述详细阐述1xx - 信息性响应 (Informational)2xx - 成功 (Successful)3xx - 重定向 (Redirection)4xx - 客户端错误 (Client Error)5xx - 服务器错误 (Server Error)HTTP 状态码速查表参考以及更多更详细的状态码查询写在前面 你…

从防抖节流到链表树:编程世界中的抽象优化艺术

从防抖节流到链表树:编程世界中的抽象优化艺术 在编程的知识体系中,有些概念看似毫不相关,却在底层逻辑上有着惊人的相似之处。防抖与节流、链表与树,这两组分属不同领域的概念,正是这种思维共性的典型代表。它们不仅展…

第三阶段数据-3:数据库脚本生成,备份与还原,分离与附加

1_生成数据库脚本(1)在数据库上右键选择任务(2)选择生成脚本(3)选择下一步,如果下次不想显示此页面,可勾选不再显示此页(4)如果导出全部数据,选择…

React框架超详细入门到实战项目演练【前端】【React】

React框架 1.前端展示解释 当客户端访问服务器时,会从服务器中下载很多静态文件到本地,比如css、js等前端渲染文件 下载完成之后浏览器会将这些文件组合形成前端页面渲染出来。 2.React概述 React是一个专注于构建用户界面的JavaScript库,…

本地部署的终极多面手:Qwen2.5-Omni-3B,视频剪、音频混、图像生、文本写全搞定

Qwen2.5-Omni-3B是什么? Qwen2.5-Omni-3B 是由阿里巴巴 Qwen 团队推出的一款轻量级多模态大模型,作为 Qwen2.5-Omni-7B 的高效优化版本,专为消费级硬件环境量身打造。该模型具备处理文本、音频、图像和视频等多种模态输入的能力,…

连续空间强化学习:策略输出的两种形态 —— 概率分布与确定性动作

在强化学习的世界里,智能体与环境的交互核心是 “动作选择”。当面对离散动作空间(如围棋的落子点、游戏的按键操作)时,智能体可以直接枚举或概率选择有限的动作;但在连续动作空间中(如机器人关节角度、无人…

IT运维背锅权限泄露?集中式管控如何化解风险?

在企业数字化转型的浪潮中,IT运维团队常常被推到风口浪尖。员工离职后权限未及时回收、账号共享导致数据泄露、跨系统权限配置不一致……这些问题一旦暴露,IT运维往往成为“背锅侠”。权限泄露不仅威胁企业数据安全,还可能导致合规性风险&…