悲观锁和乐观锁如何选择

    悲观锁,它指的是对数据被外界修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。

    乐观锁,相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制,只有在真正修改数据时才加锁,更容易理解的思想就是CAS。

    其实可以简单理解为乐观锁就是悲观锁的一种改良或优化的一种锁机制,这中优化不能单单的理解为加锁的位置和粒度的改变,这是表象,而更重要的是加锁的资源花费上的优化,更有甚者直接在指令级实现了乐观锁(没有加锁的资源花费)。那我们可以称悲观锁叫做重锁,乐观锁叫做轻锁,以下的讨论就是针对这个重轻来展开,被且证明如果离开重锁和轻锁的区别,那悲观锁和乐观锁将基本上没有区别。

大家都喜欢例子(不是特别恰当):有人向小王的账号打钱

    步骤1 获取小王账户金额x
    步骤2 z = 账户原金额x + 要打的钱y
    步骤3(乐观锁) 比较现在账号金额是否和步骤1的获取的金额相同
    步骤4 设置小王账户金额为z

    场景1:假设只有一个线程,没有任何竞争关系
        悲观锁:在步骤1时对小王的账户加锁。总加锁次数1
        乐观锁:在步骤3时对小王的账户加锁。总加锁次数1

    场景2:假设有两个线程同时并行访问,存在两个竞争者
        悲观锁:线程1在步骤1加锁账户,线程2放入队列等待,线程1执行完notify线程2,线程2加锁账户,执行完。总加锁次数2
        乐观锁:线程1在步骤3加锁,执行成功,线程2在步骤3加锁,执行失败,重新执行,重新再步骤3枷锁,执行成功。总加锁次数3

    场景3:现在扩展到N个线程并行访问,存在N个竞争者
        悲观锁:线程1在步骤1加锁账户,其余线程加入等待队列,线程1执行成功后,随机notify一个等待线程执行,以此往复,直到所有线程执行完毕。总加锁次数N
        乐观锁:线程1在步骤3加锁,执行成功,其余线程在步骤3加锁,执行失败,重新执行,其余线程继续重新执行,直到所有都执行完毕。总加锁次数为 1+2+3+…+N

    根据上面总结的加锁次数(乐观锁=1+…+N,悲观锁=N),可以得出如果两种锁加锁耗费资源相同的情况下悲观锁基本优于乐观锁,但是现实中往往就是因为乐观锁加锁所消耗的资源小于悲观锁,所以乐观锁在很多场景中使用,特别是竞争少(读多写少)的场景。
    现假设悲观锁加锁消耗的资源为10,乐观锁加锁消耗的资源为1,加10次乐观锁和加1次悲观锁的资源消耗是一样的。在这样的假设下就可以很明确的算出多少竞争情况下用乐观锁,多少情况下用悲观锁。可得出以下公式算出N这个平衡点:
        10*N = 1+2+…+N
        计算得到 N = 19
    那明显如果在10:1的资源消耗下,如果线程竞争大于19个,则悲观锁合适,如果竞争小于19个,则使用乐观锁更合适。根据本人实际工作经验,再系统如果竞争常大于3个以上,直接选择悲观锁就好了。

PS:这里将其它因素(悲观锁中上下文的切换,乐观锁中程序的不必要执行过程等等因素)弱化,只考虑加锁所消耗的资源。读者再考虑自己系统时需全面考虑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值