volatile和锁的简单总结

本文介绍了volatile关键字在并发编程中的作用及其实现原理,并探讨了Java中锁的不同级别,包括偏向锁、轻量级锁和重量级锁的工作机制及其适用场景。

volatile


volatile在转成汇编的时候,会加一条lock指令前缀,该指令的作用:
1.对变量值的改动会引起处理器的缓存刷新到主内存
2.导致其他处理器的缓存会无效
适用于一下的场景:
1.运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值
2.变量不需要与其他状态变量共同参与不变约束
   i++,进行汇编之后是四句指令,先读取i,然后把i+1赋值给i,这依赖当前变量的值,所以并不是线程安全的。如果是单一线程,则肯定是安全的。
   a线程拿的时候是最新的,拿完之后,还要进行add和赋值操作,主内存已经被更改过了。只能保证拿的时候是最新的,当前线程再操作其他指令的时候不能保证了。
   对于2也是同样的例子,if(bo1)是原子性的,但是对于if(bo2&&bo1)并不是原子性的


偏向锁、轻量级锁、重量级锁


偏向锁:第一个线程过来看对象头里面是否有当前线程id,如果没有,则用cas设置当前线程id存储在mark word,再执行该同步块,则不需要经常任何同步操作。
                当另外一个线程尝试获取锁,偏向模式宣告结束。如果锁处于锁定状态,则升级成为轻量级锁(01),否则撤销偏向到未锁定状态(00)。
(适用的场景是单个线程操作,如果多个线程竞争存在锁消除和升级的消耗)
轻量级锁:线程访问同步块,cas修改mark word 指向到当前线程。下次执行直接判断mark word 指向的是不是当前线程,是则可以直接执行同步体。
                   释放锁的过程也是通过cas 去替换回来,成功表示同步过程完成。失败表示其他线程在竞争已经进入阻塞状态了,释放锁的同时还要唤醒等待中的线程。
                   其他线程来访问,也是进行cas 修改mark word ,修改失败则自旋获取锁,还是失败,修改锁为重量级锁进入阻塞状态
重量级锁即传统的锁机制

### Java 中 `volatile` 关键字与乐观、悲观的区别 #### 1. **Volatile 的作用** `volatile` 是一种轻量级的同步机制,主要用于保证变量的可见性禁止指令重排序。它并不能提供原子性操作的支持[^3]。 - 可见性:当一个线程修改了某个被 `volatile` 修饰的变量时,新值对于其他线程立即可见。 - 禁止重排序:编译器处理器不会对 `volatile` 修饰的变量进行指令重排序。 #### 2. **Volatile 悲观的关系** 悲观通常通过显式的机制(如 `synchronized` 或 `ReentrantLock`)来实现,这些提供了互斥访问的能力,从而避免多个线程同时修改共享资源。然而,`volatile` 并不能替代悲观,原因如下: - 悲观不仅保证了可见性,还提供了排他性的访问控制,而 `volatile` 仅能解决可见性问题。 - 如果需要保护一段代码区域或者复杂的业务逻辑,悲观是必需的选择,因为它可以阻止其他线程进入临界区[^1]。 #### 3. **Volatile 乐观的关系** 乐观并不依赖于传统的机制,而是基于版本号或 CAS(Compare And Swap)算法来实现无化并发控制。以下是两者之间的关系: - 在乐观中,`volatile` 常用于修饰共享变量,以确保其可见性。例如,在使用 CAS 操作时,目标变量必须由 `volatile` 修饰,以便其他线程可以看到最新的值[^3]。 - 乐观的核心在于尝试更新数据而不定它,只有在检测到冲突时才会采取补偿措施(如重试)。因此,`volatile` 提供的基础保障使得乐观能够在高并发环境下高效运行。 #### 4. **三者的对比总结** | 特性 | Volatile | 悲观 | 乐观 | |-----------------|------------------|-------------------|------------------| | 主要功能 | 数据可见性 | 排他性访问控制 | 非阻塞并发控制 | | 是否支持原子性 | 否 | 是 | 是 | | 使用场景 | 单个变量的可见性 | 复杂业务逻辑 | 高并发读操作 | | 性能开销 | 较低 | 较高 | 较低 | #### 示例代码 以下是一个简单的例子展示如何结合 `volatile` 实现乐观: ```java public class OptimisticLockExample { private volatile int value; // 必须用 volatile 修饰 public boolean compareAndSet(int expected, int newValue) { if (value == expected) { // 检查当前值是否等于预期值 this.value = newValue; // 更新为新值 return true; } return false; } public static void main(String[] args) throws InterruptedException { OptimisticLockExample example = new OptimisticLockExample(); Thread t1 = new Thread(() -> { while (!example.compareAndSet(0, 1)) {} // 尝试将值从 0 改为 1 }); Thread t2 = new Thread(() -> { try { Thread.sleep(50); // 让 t1 先执行一段时间 } catch (InterruptedException e) {} example.value++; // 修改共享变量 }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(example.value); } } ``` 在这个例子中,`volatile` 确保了 `value` 的可见性,而 `compareAndSet` 方法实现了类似于 CAS 的行为。 --- ###
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值