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


volatile 和 synchronized 的区别

在 Java 并发编程中,volatilesynchronized 是两种常用的同步机制,但它们的适用场景和底层原理有显著差异。以下是两者的详细对比:


1. 核心功能对比

特性 volatile synchronized
原子性 不保证复合操作的原子性(如 i++)。 保证代码块或方法的原子性。
可见性 强制变量读写直接操作主内存,保证可见性。 通过锁的释放/获取强制同步内存,保证可见性。
有序性 禁止指令重排序(内存屏障)。 通过锁规则保证临界区内的操作有序性。
线程阻塞 无阻塞,轻量级。 可能引发线程阻塞(锁竞争时)。
适用场景 单写多读、状态标志。 复合操作、临界区资源保护。

2. 原子性

  • volatile

    • 不保证原子性,仅确保单次读/写操作的原子性。

    • 示例

      java 复制代码
      volatile int count = 0;
      count++; // 非原子操作(实际是 read-modify-write)

      多线程并发时,count++ 可能导致数据竞争。

  • synchronized

    • 保证原子性,锁内的所有操作作为一个整体执行。

    • 示例

      java 复制代码
      synchronized (lock) {
          count++; // 原子操作
      }

3. 可见性

  • volatile

    • 通过内存屏障强制线程每次读写 volatile 变量时直接操作主内存,跳过工作内存(CPU 缓存)。

    • 示例

      java 复制代码
      volatile boolean flag = true;
      // 线程1修改 flag 后,线程2立即可见
  • synchronized

    • 线程进入同步块时清空工作内存,从主内存重新加载变量;退出同步块时将变量写回主内存。

    • 示例

      java 复制代码
      synchronized (lock) {
          // 操作共享变量
      }

4. 有序性

  • volatile

    • 通过插入内存屏障(StoreStoreStoreLoad 等)禁止编译器和处理器对 volatile 变量的读写操作进行重排序。

    • 示例 :双重检查锁定(DCL)中防止对象未初始化就被引用。

      java 复制代码
      private static volatile Singleton instance;
  • synchronized

    • 通过"锁规则"实现有序性:同一时刻只有一个线程能执行同步块,天然保证操作按代码顺序执行。

    • 示例

      java 复制代码
      synchronized (lock) {
          // 临界区内的操作不会重排序到锁外
      }

5. 性能开销

  • volatile

    • 轻量级:仅通过内存屏障限制重排序,无线程阻塞和上下文切换开销。
    • 适用场景:适合低竞争或单写多读场景(如状态标志)。
  • synchronized

    • 重量级:涉及锁竞争、内核态切换(重量级锁)和线程阻塞,开销较大。
    • 优化机制:锁升级(偏向锁 → 轻量级锁 → 重量级锁)减少无竞争时的开销。
    • 适用场景:高竞争或需要复合原子操作的场景(如计数器、资源池)。

6. 底层实现

  • volatile

    • 内存屏障 :JVM 在字节码层面插入屏障指令(如 StoreStoreLoadLoad)。
    • 硬件支持:依赖 CPU 的缓存一致性协议(如 MESI)强制刷新内存。
  • synchronized

    • Monitor 机制:基于对象头的 Mark Word 实现锁状态管理(无锁、偏向锁、轻量级锁、重量级锁)。
    • 内核态操作:重量级锁依赖操作系统的互斥量(Mutex)实现线程阻塞。

7. 实际应用示例

(1) volatile 适用场景
  • 状态标志

    java 复制代码
    volatile boolean shutdownRequested = false;
    public void shutdown() { shutdownRequested = true; }
    public void doWork() { while (!shutdownRequested) { /* ... */ } }
  • 单例模式(DCL)

    java 复制代码
    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;
        }
    }
(2) synchronized 适用场景
  • 线程安全的计数器

    java 复制代码
    public class Counter {
        private int count = 0;
        public synchronized void increment() { count++; }
        public synchronized int getCount() { return count; }
    }
  • 资源池管理

    java 复制代码
    public class ConnectionPool {
        private final LinkedList<Connection> pool = new LinkedList<>();
        public synchronized Connection getConnection() {
            while (pool.isEmpty()) wait();
            return pool.removeFirst();
        }
        public synchronized void release(Connection conn) {
            pool.addLast(conn);
            notifyAll();
        }
    }

8. 总结对比表

维度 volatile synchronized
原子性 仅单次读/写原子,不保证复合操作。 保证代码块或方法的原子性。
可见性 直接操作主内存,强制刷新。 通过锁同步内存。
有序性 禁止指令重排序。 通过锁规则保证临界区有序。
线程阻塞 无阻塞。 可能阻塞(锁竞争时)。
性能开销 低。 高(尤其是重量级锁)。
适用场景 状态标志、单例模式(DCL)。 复合操作、资源竞争、线程间协作。

选择建议

  • 使用 volatile 的情况

    • 变量被多个线程访问,但只有一个线程修改。
    • 需要禁止指令重排序(如 DCL 单例模式)。
  • 使用 synchronized 的情况

    • 需要原子性操作(如 i++、复合逻辑)。
    • 多线程竞争同一资源(如连接池、计数器)。
相关推荐
吃好睡好便好4 小时前
提取矩阵某一行或某一列元素
开发语言·人工智能·线性代数·算法·matlab·矩阵
better_liang7 小时前
每日Java面试场景题知识点之-消息队列MQ核心场景与实战
java·面试·kafka·消息队列·rabbitmq·rocketmq·mq
小江的记录本7 小时前
【JVM虚拟机】垃圾回收GC:四种引用类型:强引用、软引用、弱引用、虚引用(附《思维导图》+《面试高频考点清单》)
java·jvm·spring boot·后端·python·spring·面试
小马爱打代码7 小时前
Spring源码 第四篇:Spring 5 源码深度拆解:AOP 全流程核心原理
java·后端·spring
deepin_sir7 小时前
10 - 函数
开发语言·python
better_liang7 小时前
每日Java面试场景题知识点之-SpringBoot启动流程
java·面试·springboot·源码解析·启动流程
RyFit7 小时前
Java + AI 实战:Spring AI 从入门到企业级落地
java·人工智能·spring
z落落8 小时前
C#String字符串
开发语言·c#·php
Raink老师8 小时前
【AI面试临阵磨枪-69】如何设计一个支持百万级工具的 Agent 系统?如何快速路由与选择工具?
人工智能·面试·职场和发展
猫头虎-前端技术8 小时前
JS 作用域与闭包:从变量提升到闭包陷阱的超详细解析
开发语言·javascript·云计算·bootstrap·ecmascript·openstack·perl