多种锁策略

乐观锁与悲观锁

        乐观锁:这个锁认为出现锁竞争大概率比较小(当前场景中,线程数目比较少,不太涉及锁竞争),工作量比较小,付出的代价也比较少。

        悲观锁:这个锁认为出现锁竞争大概率比较大(当前场景中,线程数目比较多,非常可能涉及锁竞争),工作量比较大,付出的代价也比较多。

        操作系统中的Mutex就是一个典型的悲观锁。Java中的synchronize既属于乐观锁也属于悲观锁,会根据当前锁冲突的状况来切换模式。

读写锁

        这是一种特殊的锁,将读操作和写操作分别加锁,能够进一步减少锁冲突。一般具有以下三种情况:

读加锁和读加锁之间不发生互斥。

读加锁和写加锁之间发生互斥。

写加锁和写加锁之间发生互斥。

根据这三种情况不难判断出该锁更加适用于少写多读的场景当中。

重量型锁和轻量型锁

        这两种锁非常类似于乐观锁和悲观锁,重量型锁大概率也是悲观锁,轻量型锁大概率也是乐观锁。乐观锁和悲观锁根据锁冲突来划分的,而重量型锁和轻量型锁根据工作量来划分的。

        轻量型锁的实现:

        1.如果同步对象没有被锁定,则在虚拟机在当前线程的栈帧中划分一个记录锁空间,存储锁对象目前Mark Word的拷贝。

        2.虚拟机尝试使用CAS将Mark Word更新为指向锁的记录指针。

        3.如果更新成功则表示这该线程拥有锁,锁标记为00;如果更新失败,就会检查Mark Word是否指向当前线程的栈帧,如果是则说明当前线程已经获取到锁,直接进入同步状态,如果不是则说明锁被另一个线程锁获取到了,这时就不再是轻量型锁了,而是膨胀为重量型锁。

公平锁和非公平锁

        遵循先来后的加锁顺序称为公平锁,不遵循则成为非公平锁。一般的线程的调度是不确定的,因此默认不做任何处理的锁就是非公平锁,实现公平锁则需要额外的处理。

可重入锁和不可重入锁

        一个线程对同一把锁进行两次加锁,若没有问题则成为可重入锁,若存在问题则成为不可重入锁。synchronized就属于一种可重入锁,通过对synchronized我们来了解一下可重入锁的机制。

        在synchronized当中持有哪个线程获取到锁并且将会维护一个计数器,当该线程再次遇到加锁状况时并没有真正的加锁,而是计数器自增,同理可的当遇到解锁时并不会真正的解锁,而是计数器自减,直到计数器为0时才会真正地解锁。

死锁

        死锁的出现往往伴随着线程挂掉等严重的Bug的出现:

        1.一个线程一把锁之间通过可重入锁可完美的解决这个问题。

        2.两个线程两把锁,线程一获取到锁A,在获取锁B,线程二获取到锁B在获取锁A,那么这个时候,线程一想要获取锁B则需要线程二解开锁B,而线程二想要获取锁A则需要线程一解开锁A,这样就形成了环路等待。

        3.N个线程M把锁,与2情况相同原因,形成了环路等待。

        解决方法:

        1.一般的在锁当中不要轻易的加锁,不过说起来容易做起来难,很大的概率根据需求分析不可避免的锁上加锁。

        2.约定一个固定的加锁顺序,例如要先加锁1,再加锁2,再加锁3。这样不会形成环路等待。

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值