乐观锁与悲观锁的区别:
乐观锁:在更新数据的时候其他线程争抢这个共享变量的概率非常小,所以更新数据的时候不会对共享数据加锁。但是在正式更新数据之前会检查数据是否被其他线程改变过,如果未被其他线程改变过就将共享变量更新成最新值,如果发现共享变量已经被其他线程更新过了,就重试,直到成功为止。CAS机制就是乐观锁的典型实现。
悲观锁:在更新数据的时候大概率会有其他线程去争夺共享资源,所以悲观锁的做法是:第一个获取资源的线程会将资源锁定起来,其他没争夺到资源的线程只能进入阻塞队列,等第一个获取资源的线程释放锁之后,这些线程才能有机会重新争夺资源。synchronized就是java中悲观锁的典型实现,synchronized使用起来非常简单方便,但是会使没争抢到资源的线程进入阻塞状态,线程在阻塞状态和Runnable状态之间切换效率较低(比较慢)。
适用场景
乐观锁: CAS机制, 版本号机制
悲观锁: 对代码块加锁(如Java的synchronized关键字),也可以是对数据加锁(如MySQL中的排它锁)
优缺点 使用场景
当竞争不激烈 (出现并发冲突的概率小)时,乐观锁更有优势,因为悲观锁会锁住代码块或数据,其他线程无法同时访问,影响并发,而且加锁和释放锁都需要消耗额外的资源。
当竞争比较激烈(并发冲突较高时), 悲观锁更有优势, 因为乐观锁在执行更新时频繁失败,需要不断重试,浪费CPU资源。
优点
- 可以保证变量操作的原子性;
- 并发量不是很高的情况下,使用CAS机制比使用锁机制效率更高;
- 在线程对共享资源占用时间较短的情况下,使用CAS机制效率也会较高。
缺点
- ABA问题(引入版本号)
- 可能会消耗过高的CPU(不断尝试)
- 不能保证代码原子性(Java中的CAS机制只能保证共享变量操作的原子性,而不能保证代码块的原子性。)