卡码笔记
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
  • 基础与面向对象

  • 集合

  • 异常

  • 字符串

  • JVM

  • 并发与多线程

    • Java创建线程有几种方式?
    • 线程start和run的区别?
    • Java线程安全的实现?
    • synchronized和lock、reentrantlock的区别是什么?
    • 说一说你对synchronized的理解?
    • volatile关键字的作用有哪些?
    • volatile与synchronized的对比?
      • 简要回答
      • 详细回答
      • 使用场景
      • 代码示例
      • 知识图解
      • 知识扩展
    • 你知道Java中有哪些锁吗?
    • 为什么要有线程池,线程太多会怎样?
    • 说一说线程池的常用参数
    • BIO、NIO、AIO的区别
  • JDK

  • Spring

  • 设计模式

# volatile与synchronized对比

# 简要回答

  • synchronized是确保数据的一致性和线程安全,解决多个线程之间访问资源的同步性。而volatile是确保变量在多个线程的可见性和有序性。
  • volatile不需要获取/释放锁,性能较高且轻量级。
  • synchronized可以修饰方法以及代码块,volatile只能修饰变量。

# 详细回答

  1. 机制和用途:
    • synchronized用于提供线程间的同步机制,当一个线程进入一个由synchronized修饰的代码块或方法时,它会获取一个监视器锁(monitor lock),这保证了同一时间只有一个线程可以执行这段关系代码。
    • volatile用于修饰变量,当一个线程修改了一个volatile变量的值,其他线程能够立即看到修改,还可以防止指令重排序。
  2. 原子性
    • synchronized可以保证被修饰的代码块的原子性,这段代码在执行过程中不会被其他线程打断。
    • volatile只能保证单个读写操作的原子性,对于复合操作(自增、减)不能保证原子性。
  3. 互斥性
    • synchronized提供了互斥性,同一时间只有一个线程可以执行被其修饰的代码块和方法。
    • volatile没有提供互斥性,它只能保证可见性和有序性。
  4. 性能
    • synchronized的性能相对较低,因为它需要获取和释放锁。
    • volatile的性能较高,因为它不需要获取和释放锁,更加轻量级,不过提供的同步级别较低。
  5. 使用范围
    • synchronized可以修饰方法以及代码块。
    • volatile只能修饰变量。

# 使用场景

需求 选volatile 选synchronized
操作类型 简单无复合 复合、多步操作
原子性 无 有
性能 追求极致性能(轻量) 允许性能损耗(强同步保证)
线程协作 仅状态传递 有协作(如等待/唤醒机制)

# 代码示例

  1. volatile状态标记
private volatile boolean isRunning = true;

// 线程A:修改状态(一次写)
public void stop() { isRunning = false; }

// 线程B/C:读取状态(多次读)
public void work() { while (isRunning) { ... } }
1
2
3
4
5
6
7
  1. volatile禁止指令重排序
private static volatile Singleton instance;
public static Singleton getInstance() {
    if (instance == null) {
        synchronized (Singleton.class) {
            if (instance == null) {
                instance = new Singleton(); // volatile 禁止此处重排序
            }
        }
    }
    return instance;
}
1
2
3
4
5
6
7
8
9
10
11
  1. synchronized保证复合操作原子性
private int count = 0;

// 多线程同时调用,需保证count++的原子性
public synchronized void increment() { count++; }
1
2
3
4
  1. synchronized多变量
private int total;
private int used;

// 保证total和used的同步更新
public synchronized void allocate(int amount) {
    if (used + amount <= total) {
        used += amount;
        // 其他依赖used和total的操作...
    }
}
1
2
3
4
5
6
7
8
9
10
  1. volatile和synchronized实现单例模式
public class Singleton {
    // 1. volatile修饰单例引用,禁止指令重排序
    private static volatile Singleton instance;

    // 2. 私有构造器,防止外部实例化
    private Singleton() {}

    // 3. 双重检查锁定获取实例
    public static Singleton getInstance() {
        // 第一次检查:避免不必要的同步(提高性能)
        if (instance == null) {
            // 同步块:保证只有一个线程进入初始化流程
            synchronized (Singleton.class) {
                // 第二次检查:防止多线程并发时重复初始化
                if (instance == null) {
                    // 若不加volatile,可能发生指令重排序导致的问题
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 知识图解

  1. volatile关键字的作用示意图

image

  1. synchronized底层示意图

image

  1. 使用volatile和synchronized的单例模式 image

# 知识扩展

  1. 面试官可能追问:
  • Q1:volatile的可见性是通过内存屏障实现的,具体会插入哪些内存屏障?这些内存屏障如何阻止指令重排序?
    1. 对于写操作,在写操作前插入StoreStore屏障,在写操作后插入StoreLoad屏障。
    2. 对于读操作,在读操作前插入LoadLoad屏障,在读操作后插入LoadStore屏障。
  • Q2:当volatile变量和synchronized代码块同时修饰同一变量时,会有冲突吗?执行优先级如何?
    1. 当volatile变量和synchronized代码块同时作用于同一变量时,不会产生冲突,两者的作用是互补而非对立的。它们的执行逻辑遵循 Java 内存模型(JMM)的规范,存在明确的协作关系而非 “优先级” 之分。
  • Q3:synchronized的wait()/notify()机制为什么必须在同步块中使用?volatile能否实现类似的线程间通信?
    1. wait()/notify()是synchronized机制中用于线程间协作的核心方法,必须在同步块中使用。
    2. wait()会释放锁并且阻塞当前线程,notify()则会唤醒一个等待该锁的线程,二者都基于当前线程有锁的前提。如果不在同步块中调用可能会抛出异常。
    3. volatile可以实现简单的线程状态传递,无法替代synchronized的线程协作机制,没有精确唤醒能力以及原子性保证。
  • Q4:双重检锁已经有了synchronized,为什么还要使用volatile?
    1. 第一行代码不在同步代码块之内,可能会出现对象地址不为空,内容为空情况。
    2. 代码在编译运行时可能会出现重排序,在多线程环境下可能会出现报错。
Last Updated: 3/10/2026, 6:08:48 PM

← volatile关键字的作用有哪些? 你知道Java中有哪些锁吗? →

评论

验证登录状态...

侧边栏
夜间
卡码简历
代码随想录
卡码投递表🔥
2026群
添加客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记
鼓励/支持/赞赏Carl
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪