以解决并发问题来说,乐观锁一般是数据库最常用的手段之一,小伙伴们知道一般乐观锁都会在哪些业务场景里实现吗?它又有几种实现方式呢?快跟小编来了解看看吧。
一、乐观锁实现方式及基础概念
乐观锁基础概念
乐观锁,它是一种相对悲观锁而言的,非常乐观的机制,这个乐观锁机制会假设数据一般情况下不会造成冲突,所以数据已经在进行提交更新的时候,乐观锁才会正式对数据的冲突与否进行检测,如果发现冲突,就会返回给用户错误的信息,让用户自己决定如何去做。
乐观锁相信事务之间数据竞争概率是比较小的,因此它会尽可能的直接做下去,一直到提交的时候才去锁定,所以不会产生任何锁和死锁。
乐观锁机制因为是相对于悲观锁而言的,所以它采用了更加宽松的加锁机制。这也是为了避免可能的数据库幻读、业务处理时间过长等等原因而引起数据处理错误的一种机制,但乐观锁一般不会去刻意使用数据库本身的锁机制,它会依赖数据本身来保证数据的正确性。
乐观锁实现方式
a 版本号机制
这个机制一般是说在数据表中加上一个数据库版本号version字段,它会表述数据被修改的次数,当数据被修改时,它的version 值会加1。
如:当线程1需要更新数据值时,在读取数据的同时也会读取 version 值,数据提交更新时,如果刚才读取到的 version 值为当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功。
b CAS 算法
CAS(compare and swap) 比较并交换,有三个操作数,内存地址V ,预期值B,要替换得到的目标子A;
CAS指令执行时,它会比较自己的内存地址V与预期值B是否相等,如果相等则将A赋给B,如果不相等就会循环比较到相等为止,它的整个比较赋值操作都是一个原子操作。
CAS缺点:
1)循环时间长:当内存地址V与预期值B不相等时会一直循环比较直到相等,
2)只能保证一个共享变量的原子操作
3)如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那么我们就能说明它的值没有被其他线程修改过吗?很明显不是,因为在这段时间内它的值可能被改为其他值,然后又被改回A,那CAS操作就会认为它从来没被改过,这个问题一般被叫做 CAS 操作的“ABA” 问题。
二、乐观锁一般使用场景
a乐观锁适用于线程已经发生冲突,不太严重,但还是有一点严重的样子。这是因为如果要使用Synchronized关键字来进行线程阻塞和唤醒切换以及用户内核态间的切换操作的话会额外浪费极多cpu资源,反而因为CA是基于硬件实现的,不用进入线程内核,不需要切换线程,操作自旋几率较少,所以可以获得更高的性能。
b一般来说,乐观锁只有在数据修改的时候才会判断期间有无线程更新数据,所以适用于线程冲突较小的场景,如果经常发生产生冲突,上层应用会不断的进行retry,这样反而会降低性能,所以这种情况下不建议适用乐观锁。
以上就是关于乐观锁使用场景及实现方式的所有内容了,更多乐观锁相关java常见问答知识请关注我们了解详情吧。
推荐阅读: