一篇文章彻底搞懂Synchronized 和 Volatile,看完涨薪50%!

开发 前端
小米是一家互联网大厂的Java开发工程师,最近在准备面试题。他的朋友小明在另一家公司面试Java后端工程师,面试回来一脸生无可恋:“面试官上来就问 synchronized 和 volatile 的区别,我结巴了半天,最后被怼得体无完肤!”

故事背景

小米是一家互联网大厂的Java开发工程师,最近在准备面试题。他的朋友小明在另一家公司面试Java后端工程师,面试回来一脸生无可恋:“面试官上来就问 synchronized 和 volatile 的区别,我结巴了半天,最后被怼得体无完肤!” 小米哈哈大笑:“这个问题很好回答啊,我来给你讲讲。” 于是,一场关于 Java 并发的讨论就此展开……

图片图片

synchronized 和 volatile 的基本概念

小米清了清嗓子,开始讲解:

“我们写 Java 代码时,多线程编程是绕不开的一个话题,而 synchronized 和 volatile 这两个关键字,都是 Java 提供的线程同步手段。”

1、synchronized:独占锁,保证原子性和可见性

  • synchronized 是 Java 提供的关键字,它表示只有一个线程可以获取作用对象的锁,进入同步代码块,其他线程必须等待。
  • 这样可以防止多个线程并发修改共享资源,保证变量的可见性和原子性,防止线程安全问题。

2、volatile:内存可见性,防止指令重排序

volatile 关键字用于修饰变量,它告诉 CPU 和编译器:

  • 这个变量不能被缓存,必须从主存(内存)中读取。
  • 禁止指令重排序,防止CPU对代码执行顺序进行优化,导致多线程环境下的程序异常。

小明点点头:“听起来好像都能用来解决并发问题啊?它们的区别到底在哪?”

synchronized 和 volatile 的核心区别

小米笑着说:“这正是面试官的坑点!虽然它们都跟线程安全有关,但作用完全不同。”

1、修饰对象的范围不同

图片

小米举例:“比如你有一个 count 变量,你可以用 volatile 让它的修改对所有线程可见。但如果你要保证 count++ 这个操作的原子性,那 volatile 就不行了,必须用 synchronized。”

2、是否保证原子性

图片

小明皱眉:“等等,那如果 volatile 不能保证原子性,它的用武之地在哪?”

小米解释:“volatile 适用于单一变量的状态标记,比如双重检查锁(DCL)模式下的 instance 变量,或者是 boolean flag 这样的简单开关变量。而 synchronized 适用于复杂逻辑操作,比如 count++ 这种需要原子性保护的操作。”

synchronized 和 volatile 的其他区别

小米继续深入讲解:

1、是否会造成线程阻塞

图片图片

2、是否会被编译器优化

图片图片

小明惊讶:“原来 Java 还这么智能,synchronized 还能被优化?”

小米点头:“对的!Java 1.6 以后,synchronized 进行了很多优化,比如:

  • 偏向锁:如果一个线程一直在使用同一个锁,JVM 就不会频繁地加锁和释放锁。
  • 轻量级锁:多个线程尝试竞争锁时,不会立即进入阻塞状态,而是使用 CAS 方式尝试加锁,提高性能。
  • 锁消除、锁膨胀:JVM 会根据实际情况优化锁的使用。”

面试中如何回答 synchronized 和 volatile 的区别

小米总结了一套“黄金答题模板”:

“如果面试官问 synchronized 和 volatile 的区别,你可以这么答:

  • volatile只能修饰变量,synchronized 既能修饰变量,也能修饰方法和代码块。
  • volatile保证变量的可见性,但不保证原子性;synchronized同时保证可见性和原子性。
  • volatile不会造成线程阻塞,而 synchronized 可能会导致线程阻塞。
  • volatile不能被编译器优化,而 synchronized 通过 JVM 的优化(如偏向锁、轻量级锁)能提高性能。
  • volatile 适用于状态标记等简单场景,而 synchronized 适用于临界区保护、多个操作组合的场景。”

小明眼睛一亮:“听你这么一说,我感觉能答出个八九不离十了!”

真实场景下的选择

小米最后补充道:“不过,面试官可能还会问你——在真实项目中该怎么选? 你可以告诉他:”

  • 如果只是想让变量的修改对所有线程可见,且不涉及复合操作(如count++),可以用 volatile。
  • 如果需要保证线程安全,操作需要原子性,那就用 synchronized(或者 Lock 机制)。
  • 如果涉及高并发,还可以考虑 ReentrantLock,它比 synchronized 更灵活。

面试官的 “坑” 及应对

小米最后提醒:“面试官喜欢挖坑,比如问你:”

1、volatile 适用于哪些场景?

  • 适用于状态标记(比如 boolean flag),单例模式的双重检查锁(DCL)。

2、为什么 volatile 不能保证原子性?

  • 因为 volatile 只是保证了线程可见性,但 count++ 这样的操作是 读取-计算-写入,中间有多个步骤,volatile 无法保证其不被其他线程干扰。

3、为什么 synchronized 能保证原子性?

  • 因为 synchronized 会让线程独占锁,保证操作的完整性,其他线程必须等待锁释放。
责任编辑:武晓燕 来源: 软件求生
相关推荐

2017-07-20 16:55:56

Android事件响应View源码分析

2019-07-23 08:55:46

Base64编码底层

2024-06-25 08:18:55

2020-06-03 11:06:26

DNS域名缓存

2013-04-15 10:59:08

iOS开发ARC版本说明

2024-05-10 08:19:59

arthasjava字节码

2019-08-13 09:00:01

内网外网通信

2021-05-27 09:01:14

Python文件读写Python基础

2021-08-17 09:55:05

JavaScript MicrotaskPromise

2021-03-08 09:15:46

日志Filebeat运维

2021-08-30 10:01:01

Map接口HashMap

2021-05-21 09:01:56

Python继承多态

2021-05-18 09:00:28

Pythonclass

2021-08-02 10:01:09

Iterator接口Java项目开发

2024-10-23 16:02:40

JavaScriptPromiserejection

2020-06-23 16:28:25

Nginx负载均衡服务器

2023-11-01 15:52:35

2020-07-28 17:27:53

Nginx 负载均衡模块

2025-01-26 15:38:11

Spring事务编程式

2020-10-09 08:15:11

JsBridge
点赞
收藏

51CTO技术栈公众号