欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > Java高频面试之并发编程-13

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

2025/5/9 21:25:49 来源:https://blog.csdn.net/2401_87189717/article/details/147774032  浏览:    关键词: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;}
}

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词