乐观锁与悲观锁
乐观锁与悲观锁的区别?
- 悲观锁:共享资源每次只给一个线程使用,其他线程阻塞,用完之后再把资源让给其他资源。但是读写锁可以多个线程同时读。
- 乐观锁:共享资源每次可以给多个线程使用,只是再提交修改的时候去验证资源是否被其他线程所修改。
使用场景:
- 悲观锁:适合写多读少的情况。
- 乐观锁:适合读多写少的情况。
缺陷:
- 悲观锁:高并发下,激烈的锁竞争会造成线程阻塞,大量的线程会导致系统上下文切换频繁,增加系统的性能开销;还有可能导致死锁。
- 乐观锁:高并发下,相比悲观锁来所,不存在锁竞争造成线程阻塞,也不会有死锁问题,性能往往更好。但是再写冲突高的场景下可能会导致ABA问题,性能忽高忽低等
CAS了解吗?原理是什么?
乐观锁一般会使用版本号机制或者CAS算法实现,CAS算法使用会多一些。值得一提的是,这里的版本号机制和CAS算法中的ABA问题的解决方案是同一个东西。
CAS算法的思想很简单,就是用一个预期值和要更新的变量值进行比较,两个值相等才会进行更新。这里的比较和修改两个步骤再CPU硬件层面是一条原子指令,是不可拆分的,这也是CAS算法的基础。
比如ConcurrentHashMap采用的就是CAS和synchronized来保证并发安全的。
原子类也是
JMM(Java memory model)
并发编程的三个重要特性
- 原子性:一个或者多个操作要么全部执行且不中断,要么全部不执行。
- 可见性:当一个线程修改了共享变量,其他线程能够立刻看到这个修改。
- 有序性:编译器优化和指令重排在多线程情况下,可能导致意外的结果。因此保证有序性可以禁止指令进行重排序优化。
实现手段
- 原子性:一般都是通过加锁去实现,当然也可以使用CAS实现。
- 可见性:
- 使用
volatile关键字 synchronized和lock同步块final关键字再构造函数中有正确初始化(没有this逃逸)
- 使用
- 有序性:
volatilesynchronized和lock同步块happens-before原则:在多线程环境中,当两个操作之间存在happens-before关系时,前一个操作的修改对后一个操作是可见的。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 coder-xuyong!
评论






