深入浅出synchronized关键字 、无状态锁、偏量锁、轻量锁、重量锁

本文介绍了synchronized锁,它能处理多线程安全隐患但会降低系统效率。JDK对其进行了升级,锁有四种状态:无状态锁、偏向锁、轻量锁、重量锁。阐述了偏向锁、轻量级锁、重量级锁的转换条件,还提到轻量级锁生效时间可配置,且除偏向锁外,锁状态只能升级不能降级。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

synchronized在做开发的时候或多或少都用过 但是对与理解方便之前只是简单的认为是一个锁 加上之后可以处理多线程下的安全隐患 但是会降低系统的效率 因为一个线程加锁之后其余线程都会在外部进行等待 殊不知其实JDK已经对其锁进行了较大规模的升级

 

锁的状态有四种  无状态锁、偏向锁、轻量锁、重量锁

在长期的实践发现 一个线程在多次调用锁的情况是时有发生的 所以当在线程第一次获取锁的时候锁会读取线程里的threadid 且记录下来 在后期如果同一个线程再次进来判断其threadid一致时就直接放行 避免开锁关锁的消耗 如果是另一个线程 就进行判断之前的线程是否为存活状态 不是的话就把锁重置为无状态锁 再让其余线程进入转化为轻量级锁 

ps:轻量级锁默认是开启且在程序执行四秒后生效 可以通过XX:BiasedLockingStartUpDelay=0取消限制 也可以那么可以通过-XX:-UseBiasedLocking = false来取消偏向锁

当第二个线程开始抢占的时候会让第二个锁先进行自旋状态 当超过一定次数(默认十次)或者当第二个线程在自旋的过程中第三个线程也进行抢占资源 那么会升级为重量级锁

注意:锁的状态除了偏向锁可以转为无状态锁 其余了只可以升级 不可以降级

<think>好的,用户之前问过Java的异常体系,现在又问volatile和synchronized的区别。这说明他们可能在学习Java并发相关的知识,或者在实际开发中遇到了多线程的问题。需要先确定用户的基础,但根据之前的回答,他们可能已经有一定的Java基础,所以这次要深入浅出地解释这两个关键字的区别。 首先,用户可能知道synchronized是用来同步的,但volatile可能不太清楚。需要明确两者的不同点,比如可见性、原子性、使用场景等。同时,用户可能想知道在什么情况下应该用哪一个,或者两者的组合使用。需要举一些例子,比如单例模式中的双重检查定,这样用户更容易理解。 另外,用户可能对内存屏障、指令重排这些底层概念不太熟悉,所以需要用更易懂的语言解释,避免过于技术化。还要注意结构清晰,分点说明区别,可能用表格对比会更直观。最后,要提醒用户常见的误区和最佳实践,帮助他们避免错误使用。</think>以下是Java中`volatile`与`synchronized`的核心区别解析: --- ### 一、本质区别对比表 | **对比维度** | `volatile` | `synchronized` | |-------------------|---------------------------------------------|-----------------------------------------| | **作用范围** | 变级别 | 代码块/方法级别 | | **内存可见性** | 保证可见性(直接读写主内存) | 保证可见性(解前同步到主内存) | | **原子性** | 不保证原子性 | 保证操作的原子性 | | **指令重排序** | 禁止指令重排序(内存屏障) | 临界区内代码有序执行 | | **阻塞机制** | 非阻塞 | 阻塞(线程竞争) | | **性能消耗** | 低(仅内存操作) | 高(上下文切换开销) | | **使用场景** | 状态标志位、双重检查 | 需要原子性操作的代码区域 | --- ### 二、内存可见性原理 #### 1. `volatile`的内存语义 ```java // volatile变写入时会立即刷新到主内存 public class Counter { private volatile int count = 0; public void increment() { count++; // 非原子操作,存在线程安全问题! } } ``` - **写操作**:在变修改后立即将值同步到主内存 - **读操作**:每次读取都直接从主内存获取最新值 #### 2. `synchronized`的可见性保证 ```java public class SafeCounter { private int count = 0; public synchronized void increment() { count++; // 原子操作 } } ``` - 进入同步块时清空工作内存 - 退出同步块时将修改刷回主内存 --- ### 三、原子性差异演示 #### 典型反例:volatile不保证原子性 ```java volatile int num = 0; // 多线程并发执行时会出现计数错误 void unsafeAdd() { num++; // 实际是read-modify-write三步操作 } ``` #### synchronized保证原子性 ```java int num = 0; // 线程安全的计数 synchronized void safeAdd() { num++; } ``` --- ### 四、禁止指令重排序 #### volatile的内存屏障(Memory Barrier) ```java // 单例模式的双重检查定 class Singleton { private volatile static Singleton instance; public static Singleton getInstance() { if (instance == null) { // 第一次检查 synchronized (Singleton.class) { if (instance == null) { // 第二次检查 instance = new Singleton(); // volatile禁止new操作的重排序 } } } return instance; } } ``` - **写屏障**:确保在volatile写之前的操作不会被重排序到写之后 - **读屏障**:确保在volatile读之后的操作不会被重排序到读之前 --- ### 五、性能对比测试 | **操作类型** | 执行时间(纳秒/op) | |-------------------|--------------------| | volatile读 | ~5-10 | | synchronized块 | ~20-100 | | CAS操作 | ~10-20 | *(数据基于x86架构测试环境)* --- ### 六、使用场景指南 #### 优先使用`volatile`的情况 1. 状态标志位(单写多读场景) ```java volatile boolean shutdownRequested; void shutdown() { shutdownRequested = true; } void doWork() { while (!shutdownRequested) { // 执行任务 } } ``` 2. 双重检查定模式(需配合volatile) #### 必须使用`synchronized`的情况 1. 复合操作(check-then-act) ```java // 不安全的实现 if (!vector.contains(element)) { vector.add(element); } // 正确的同步实现 synchronized(vector) { if (!vector.contains(element)) { vector.add(element); } } ``` 2. 需要保证原子性的代码块 --- ### 七、常见误区警示 1. **错误认知**:认为`volatile`可以替代`synchronized` - 事实:`volatile`仅解决可见性问题,不解决原子性问题 2. **危险代码示例**: ```java volatile int a = 0, b = 0; void unsafeMethod() { a++; // 非原子操作 b = a + 1; // 可能使用过期的a值 } ``` 3. **正确组合使用**: ```java // 使用volatile作为轻级状态标志 volatile boolean initialized = false; // 使用synchronized保证初始化原子性 synchronized void init() { if (!initialized) { // 初始化代码... initialized = true; } } ``` --- ### 八、底层实现原理 | **机制** | `volatile` | `synchronized` | |-------------------|-------------------------------------|-------------------------------------| | **字节码层面** | ACC_VOLATILE标志 | monitorenter/monitorexit指令 | | **CPU层面** | 内存屏障指令(如mfence) | 总线或缓存(MESI协议) | | **JVM优化** | 无优化 | 升级(->轻量锁->重量) | --- 掌握二者的核心区别,可以更精准地选择线程安全方案:需要简单可见性控制时用`volatile`,需要原子性保证时用`synchronized`,在高并发场景下可结合`java.util.concurrent`包中的更高效工具类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值