0

0

如何理解Java的原子性、可见性、有序性_多线程环境下的OOP

P粉602998670

P粉602998670

发布时间:2026-03-04 08:15:40

|

577人浏览过

|

来源于php中文网

原创

原子性指对其他线程看起来不可分割;可见性指避免线程缓存过期副本;有序性指禁止jvm/cpu重排序破坏多线程逻辑;oop并发下需将状态与同步策略绑定。

如何理解java的原子性、可见性、有序性_多线程环境下的oop

原子性不是“不可分割”,而是“对其他线程看起来不可分割”

Java里int i++看似简单,实际是读-改-写三步,多线程下可能被中断,导致结果丢失。真正原子的操作只有:基本类型赋值(除longdouble在32位JVM上)、volatile读写、以及java.util.concurrent.atomic包下的类操作。

实操建议:

  • 别依赖i++list.add()的原子性——它们都不是
  • 计数器优先用AtomicInteger,而不是synchronized包裹普通int
  • AtomicReference适合封装对象引用的原子更新,比如无锁栈/队列实现
  • 注意AtomicInteger.getAndIncrement()返回旧值,incrementAndGet()返回新值,选错会导致逻辑 bug

可见性失效不是“没刷新”,而是“线程缓存了过期副本”

JVM允许每个线程把变量副本放在本地内存(如CPU缓存、寄存器),不强制立刻同步到主内存。所以线程A改了flag = true,线程B可能永远看不到——除非加volatilesynchronized或使用final字段安全发布。

常见错误现象:

立即学习Java免费学习笔记(深入)”;

  • while(!stop)循环卡死,即使另一线程已设stop = true
  • 对象构造未完成就被其他线程看到(DCL单例中忘记volatile修饰实例字段)

关键点:

Lemonaid
Lemonaid

AI音乐生成工具,在音乐领域掀起人工智能革命

下载
  • volatile只保证单个变量的可见性和禁止重排序,不保证复合操作原子性
  • synchronized块退出时会刷出所有本地修改,进入时会清空本地缓存——这是它附带的可见性保障
  • 对象一旦通过final字段正确构造(且构造过程中没泄露this),其他线程看到该对象时,一定能看见final字段的初始化值

有序性被破坏不等于“代码乱跑”,而是“JVM或CPU重排了指令”

为了优化性能,JVM和CPU可能调整指令执行顺序,只要不影响单线程语义。但多线程下,这种重排序会让某些依赖顺序的逻辑出错。例如双重检查锁中,instance = new Singleton()可能被拆成:分配内存→写final字段→设置instance引用;而重排序后变成:分配内存→设置instance引用→写final字段——这时另一个线程可能拿到未初始化完成的对象。

控制手段有限且精准:

  • volatile写之前的所有操作,不能重排序到该写之后;volatile读之后的所有操作,不能重排序到该读之前
  • synchronized块内语句不会被重排到块外,但块之间仍可能重排
  • 不要试图靠Thread.sleep()或空循环“等一等”来解决有序性问题——它既不禁止重排,也不保证可见性

OOP在多线程下不是失效,而是“封装边界被并发穿透”

一个Counter类封装了private int count,但若暴露getCount()increment()两个非原子方法,外部调用c.getCount() + 1c.increment()就完全绕过了封装意图。OOP的“数据+行为绑定”在并发场景下需要升级为“状态+同步策略绑定”。

设计时必须明确回答:

  • 这个类是否预期被多个线程共享?如果不是,就加文档注明“not thread-safe”
  • 如果要线程安全,是用synchronized方法(简单粗暴)、ReentrantLock(支持条件、可中断)、还是无锁结构(高竞争下更优)?
  • 是否允许弱一致性?比如ConcurrentHashMapsize()不保证实时准确,但迭代时不抛ConcurrentModificationException

最容易被忽略的是:final字段的初始化时机、对象发布方式(逃逸分析失败导致堆上对象被提前看到)、以及日志/监控等副作用代码意外破坏同步边界。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

201

2023.11.20

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

104

2023.09.25

string转int
string转int

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

910

2023.08.02

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

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

600

2024.08.29

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

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

294

2025.08.29

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

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

212

2025.08.29

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

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

294

2025.08.29

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

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

105

2025.10.23

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

0

2026.03.04

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.1万人学习

C# 教程
C# 教程

共94课时 | 10.6万人学习

Java 教程
Java 教程

共578课时 | 76.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号