当前位置: 首页 > news >正文

Java高频面试之并发编程-13

hello啊,各位观众姥爷们!!!本baby今天又来报道了!哈哈哈哈哈嗝🐶

面试官:详解原子性、可见性、有序性


在并发编程中,原子性(Atomicity)可见性(Visibility)有序性(Ordering) 是确保多线程程序正确性的三大核心特性。它们共同解决了多线程环境下的数据竞争、状态不一致等问题。


1. 原子性(Atomicity)

定义

原子性指一个操作不可分割,要么完全执行成功,要么完全不执行,中间状态对其他线程不可见。

问题场景
  • 复合操作的非原子性:例如 i++ 操作实际分为三步:读取 i、计算 i+1、写回 i。多线程下,多个线程可能交替执行这些步骤,导致最终结果不符合预期。
  • 示例
    int i = 0;
    // 线程1和线程2同时执行以下代码
    i++; // 实际可能丢失部分更新
    
    若两个线程同时执行 i++,期望结果应为 2,但可能得到 1
解决方案
  • 锁机制(如 synchronized):

    synchronized (lock) {i++;
    }
    

    通过互斥锁确保同一时间只有一个线程执行代码块。

  • 原子类(如 AtomicInteger):

    AtomicInteger atomicInt = new AtomicInteger(0);
    atomicInt.incrementAndGet(); // CAS 操作保证原子性
    

    底层基于 CAS(Compare-And-Swap) 实现,无锁且高效。

  • 基本类型的原子读写
    Java 中除 longdouble 外的基本类型(如 intboolean)的读写是原子的。
    注意:32 位 JVM 中 long/double 的非原子性可能导致“写撕裂”(写入半个字)。


2. 可见性(Visibility)

定义

可见性指当一个线程修改共享变量后,其他线程能立即看到修改后的值。

问题场景
  • 工作内存与主内存不一致
    线程操作变量时,可能从工作内存(CPU 缓存)读取副本,而非主内存。未同步时,修改可能对其他线程不可见。
  • 示例
    boolean flag = true;
    // 线程1
    while (flag) { /* ... */ } // 可能死循环,即使线程2修改了flag
    // 线程2
    flag = false;
    
    线程2修改 flag 后,线程1可能无法及时感知。
解决方案
  • volatile 关键字

    volatile boolean flag = true;
    

    volatile 强制所有读写直接操作主内存,并通过内存屏障禁止重排序。

  • 锁机制(如 synchronizedLock):
    锁的释放会强制将工作内存刷新到主内存,锁的获取会清空工作内存,从主内存重新加载变量。

  • final 关键字
    正确构造的对象(无 this 逃逸),其 final 字段的初始化值对所有线程可见。

    final int x = 42; // 其他线程看到x一定是42
    

3. 有序性(Ordering)

定义

有序性指程序执行的顺序按代码的先后顺序执行,但编译器和处理器可能重排序指令以提高性能。

问题场景
  • 指令重排序导致逻辑错误
    例如双重检查锁定(DCL)单例模式中,可能返回未完全初始化的对象。
    // 错误示例
    if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton(); // 可能发生重排序}}
    }
    
    new Singleton() 的步骤可能被重排序为:分配内存 → 返回引用 → 初始化对象。其他线程可能拿到未初始化的实例。
解决方案
  • volatile 关键字

    private static volatile Singleton instance;
    

    volatile 禁止指令重排序,确保对象完全初始化后才赋值给引用。

  • Happens-Before 规则
    Java 内存模型定义的操作顺序规则,包括:

    • 程序顺序规则:单线程内代码顺序执行。
    • 锁规则:解锁先于后续加锁。
    • volatile 规则:写操作先于后续读操作。
    • 传递性:若 A 先于 B,B 先于 C,则 A 先于 C。
  • 内存屏障
    JVM 通过插入内存屏障(如 LoadLoadStoreStore)限制编译器和 CPU 的重排序。


三者的关系与对比

特性定义典型问题解决工具
原子性操作不可分割竞态条件(如 i++ 错误)synchronized、原子类、CAS
可见性修改后其他线程立即可见脏读、死循环volatilesynchronizedfinal
有序性代码顺序执行,禁止重排序对象未初始化、逻辑错误volatile、Happens-Before、内存屏障

实际应用示例

1. 原子性:银行转账
public class Account {private int balance;// 使用 synchronized 保证原子性public synchronized void transfer(Account target, int amount) {if (this.balance >= amount) {this.balance -= amount;target.balance += amount;}}
}
2. 可见性:状态标志
public class Server {private volatile boolean isRunning = true;public void stop() { isRunning = false; }public void serve() {while (isRunning) { /* 处理请求 */ }}
}
3. 有序性:单例模式(DCL)
public class Singleton {private static volatile Singleton instance;public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton(); // 禁止重排序}}}return instance;}
}

在这里插入图片描述

相关文章:

  • Go语言八股之并发详解
  • 七彩喜微高压氧舱:探索健康与康复的新维度
  • Linux 内核学习(6) --- Linux 内核基础知识
  • Advanced Installer 22.5打包windows 安装包
  • 【Bluedroid】 HID 设备应用注册与主机服务禁用流程源码解析
  • 【Mybatis-plus常用语法】
  • 实验六 基于Python的数字图像压缩算法
  • 并发设计模式实战系列(17):信号量(Semaphore)
  • PostgreSQL 查询历史最大进程数方法
  • NumPy 2.x 完全指南【一】简介
  • Linux网络编程day6 下午去健身
  • JAVA中常见队列详解-非线程安全
  • MCP系列(一)什么是MCP?
  • DMA技术原理
  • 软件系统的可观测性 Observability
  • 鸿蒙开发中对want的深入理解,want和uiability的关系-深度理解want的意思有利开发-优雅草卓伊凡
  • 聊一聊Qwen3思考模式实现以及背后原理探讨
  • 【Ollama】docker离线部署Ollama+deepseek
  • 深度学习赋能:正面吊车载箱号识别系统的核心技术
  • vue+vite难点和优化,及seo优化
  • 欧盟决意与俄罗斯能源彻底决裂之际,美国谋划新生意:进口俄气对欧转售
  • 烈士沈绍藩遗孤、革命家帅孟奇养女舒炜逝世,享年96岁
  • A股三大股指低收:银行股再度走强,两市成交11920亿元
  • 菲护卫艇企图侵闯中国黄岩岛领海,南部战区:依法依规跟踪监视、警告驱离
  • 戴维·珀杜宣誓就任美国驻华大使
  • 当年的你,现在在哪里?——新民晚报杯40周年寻人启事