在计算机中,乐观锁和悲观锁的目的都是为了保证线程安全,避免在并发场景下的资源竞争问题。
悲观锁
概念
悲观锁在访问共享资源的时候,总是假设最坏的情况,认为共享资源的每次访问都会出现问题(别的线程来修改共享资源),因此在每次获取资源时都会上锁 => 共享资源每次只给一个线程使用,其他线程被阻塞,获得共享资源的线程使用完后才会释放锁,把资源的使用权让出。
实现
Java中的synchronized
关键字和java.util.concurrent.locks.Lock
的实现类都是悲观锁思想的实现。
void f() { |
适用场景
悲观锁适合写操作多的场景,先加锁可以保证写操作时数据正确,显式的锁定之后再操作共享资源,这样可以避免频繁失败和重试影响性能,悲观锁的开销是固定的。但是,如果乐观锁解决了频繁失败和重试的问题,也可以考虑使用乐观锁,这个要根据实际情况来定。
存在的问题
高并发场景下,激烈的锁竞争会造成线程阻塞,大量的阻塞线程会导致频繁的系统上下文切换,增加系统的性能开销。同时,悲观锁还可能会存在死锁问题,影响程序的正常执行。
乐观锁
概念
乐观锁在访问共享资源的时候,总是假设最好的情况,认为共享资源的每次访问不会出现问题,线程可以不停的执行,无需加锁和等待,只需要在提交修改的时候验证共享资源是否被其他线程修改了。
实现
乐观锁一般会使用版本号机制或者CAS算法实现。
版本号机制
一般情况下,在数据表中加上一个数据版本号 version
字段,表示数据被修改的次数。当数据被修改时,version
值会+1
。当线程 A 要更新数据值时,在读取数据的同时也会读取
version
值,在提交更新时,若刚才读取到的 version
值为当前数据库中的 version
值相等时才更新,否则重试更新操作,直到更新成功。
UPDATE `table_name` SET col1 = val1, version = version + 1 WHERE `id` = id_val AND version = old_version; |
CAS算法
CAS,Compare And Swap,思想就是用一个预期值和要更新的变量值比较,只有两个值相等的时候才会更新。
CAS是一个原子操作,底层依赖一条CPU的原子指令。
原子操作:最小不可拆分的操作,操作一旦开始执行,不能被打断。
CAS操作的三个操作数:
// Var: 要更新的变量值 |
当且仅当
Var == Expected
时,CAS才会通过原子方式用新值New来更新Var的值,如果不相等,说明已经有其他线程更新了Var,当前线程放弃更新。
当多个线程同时使用CAS操作一个变量时,只有一个线程会成功更新,其余都会失败,失败的线程并不会被挂起,仅仅是被告知失败,同时允许再次尝试,也允许放弃操作。
Java的sun.misc.Unsafe
类中提供了三个CAS本地方法:
/** |
Java中java.util.concurrent.atomic
包下的原子类使用了乐观锁的一种实现方式CAS。
适用场景
乐观锁通常多于读操作多的情况下,竞争较少,这样可以避免频繁加锁影响性能。
乐观锁主要针对的对象是单个共享变量。
存在的问题
ABA问题
问题:如果一个变量 V 初次读取时值是A,并且在准备更新时检查到它的值仍然是A,这就能说明它的值没有被其他线程修改过了吗?
很明显是不能的,因为在这段时间它的值可能被改为其他值,最后又改回了A,那 CAS 操作就会误认为它从来没有被修改过。
解决思路:在变量前面追加上版本号或者时间戳。
Java中的AtomicStampedReference
类就是用来解决ABA问题的,其中的方法compareAndSet
就是先比较当前引用是否等于预期引用,以及当前标志是否等于预期标志,如果都相等,才以原子方式将该引用和该标志的值设置为给定的新值。
/** |
自旋时间长,开销大
CAS 经常会用到自旋操作来进行重试,即不成功就一直循环执行直到成功。如果长时间不成功,会给 CPU 带来非常大的执行开销。
pause指令是一种CPU指令,它可以让CPU暂停执行一段时间,以便让其他线程有机会执行。在Java中,如果JVM支持pause指令,那么在CAS操作中使用pause指令可以减少自旋时间,从而提高性能。
需要注意的是,并不是所有的处理器都支持pause指令,因此,如果要使用pause指令来优化CAS操作,需要先检查处理器是否支持该指令。另外,即使处理器支持pause指令,也不能保证在所有情况下都能提高性能,因为性能的提升取决于具体的应用场景和代码实现。
参考文章
- https://javaguide.cn/java/concurrent/optimistic-lock-and-pessimistic-lock.html
- https://blog.csdn.net/TZ845195485/article/details/109398072