在Java里原子性可见性有序性如何理解_Java并发特性解析

落瑶大大_9482

落瑶大大_9482

2026-01-30

337人浏览

原创

Java并发中原子性、可见性、有序性是保障共享变量操作正确的三层约束,共同构成happens-before规则基础;volatile提供可见性与部分有序性但不保证原子性,synchronized三者兼具,AtomicInteger通过CAS融合三者。

在java里原子性可见性有序性如何理解_java并发特性解析

Java 并发中的原子性、可见性、有序性不是并列的三个独立概念,而是围绕「多线程环境下对共享变量操作的行为约束」形成的三层保障——其中原子性解决“执行不中断”,可见性解决“改了别人看不看得见”,有序性解决“代码写的顺序和实际执行顺序是否一致”。它们共同构成 happens-before 规则的基础,而 happens-before 才是真正用来推理正确性的工具。

原子性 ≠ 单条语句不拆分,而是「不可分割的执行单元」

很多人以为 i++ 是原子的,其实它被编译为「读取 i → 加 1 → 写回 i」三步,中间可被线程抢占。即使 int 类型的读写在 JVM 层面通常是原子的(对 32 位变量),但复合操作仍不安全。

  • AtomicInteger.incrementAndGet() 是原子的,因为底层用 CAS(Compare-And-Swap)指令保证整个操作不可中断
  • synchronized 块或 ReentrantLock 也能提供原子性,但粒度更大、开销更高
  • long 和 double 的非 volatile 读写,在 32 位 JVM 上可能不是原子的(JVM 规范允许分两次 32 位操作)

可见性失效常见于「线程本地缓存未及时同步」

每个线程有自己的工作内存(比如 CPU 寄存器或 L1/L2 缓存),对共享变量的修改可能只停留在本地,其他线程看不到最新值。这不是 bug,而是 JVM 为性能做的默认优化。

java-api-doc-generator
java-api-doc-generator

分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。

下载
  • volatile 强制每次读都从主内存取,每次写都立即刷到主内存,从而保证可见性
  • synchronized 在解锁前会把工作内存中变量的最新值刷新到主内存,加锁时会清空本地缓存并从主内存读取——所以它也具备可见性保障
  • 仅靠 final 字段能保证初始化完成后的可见性(构造器内写入的 final 值,其他线程看到对象引用后一定能看见该值),但不适用于后续修改
  • 没有同步机制时,哪怕只是 flag = true 这种简单赋值,另一个线程也可能永远看不到 true

有序性被重排序打破,但 happens-before 定义了哪些重排被禁止

JVM 和 CPU 都可能对指令重排序(包括编译器重排、运行期重排、内存系统重排),只要不改变单线程语义。但多线程下,这种重排可能导致诡异结果。

  • volatile 写之前的所有操作,不能被重排到写之后;volatile 读之后的所有操作,不能被重排到读之前——这就是「volatile 的禁止重排语义」
  • synchronized 的解锁操作 happens-before 后续任意线程对该锁的加锁操作,天然构成有序性边界
  • 构造器中对 final 字段的写入,happens-before 构造器结束,因此其他线程看到该对象引用时,必能看到正确的 final 值
  • 不要依赖「代码写在前面就一定先执行」——比如 a = 1; flag = true; 中,flag = true 可能先于 a = 1 对其他线程可见,除非加 volatile 或锁

真正容易被忽略的是:这三个特性从来不会单独起作用。一个 volatile 变量既提供可见性,也提供部分有序性(但不提供原子性);synchronized 同时提供原子性、可见性和有序性;而 AtomicInteger 的 compareAndSet() 方法之所以可靠,是因为它内部融合了 volatile 读写 + CAS,同时满足三者要求。写并发逻辑时,别问“我需要哪个特性”,而要问“我这个场景下,哪些操作必须构成一个 happens-before 关系”。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

java 同步机制

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.02

6819

3

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.08.29

3285

6

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

2025.08.29

4268

10

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

2025.08.29

2905

10

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

2025.08.29

4268

10

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

2025.10.23

824

4

c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

2025.10.23

794

12

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

4458

6

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

2025.12.24

1249

20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习