• 展开微博窗口
  • QQ:826945906
  • 微信:u200714928
  • 展开分类目录
胡伟

关于锁的知识的总结

1.数据库中的行锁,表锁,读锁,写锁以及syncronized实现的锁,都是悲观锁
2.innodb默认使用行锁,而行锁是基于索引的,因此要想加上行锁,在加锁时必须命中索引,否则将使用标锁。
3.乐观锁通过在表中增加一个版本号或时间戳来实现,其中,版本最常见。
4.乐观锁的原理:事务在从数据库取数据是,会将该数据的版本也取出来(v1),当事务对数据变动完毕,想要将其更新到表中时,会将之前取出的版本号v1与数据中最新的版本号v2进行比较,如果v1=v2,那么说明在此事务期间,没有其他事务对数据进行修改,此时,就允许事务对表中的数据进行修改,并且修改时版本号会加1,以此表明数据已被改动。如果v1!=v2,那么说明事务操作过程中,有其它事务对数据进行了修改,此时,一般的处理办法是通知用户,让用户重新操作。所以,乐观锁需要人为控制,而悲观锁不需要。

比较:
悲观锁:一个事务用悲观锁对数据加锁之后,其它事务将不能对加锁的数据进行除查询之外的任何操作,影响了系统的吞吐量。适合写多的场景。
乐观锁:不在数据库上加锁,任何事务都可以对数据进行操作,在更新时才进行校验,提高吞吐量。适合读多的场景。

重量级锁:拿不到该锁后,里面进入阻塞模式的锁。(线程进入阻塞状态是比较耗时的,需要,保存线程执行状态,上下文等数据,还涉及到用户态到内核态的转换,同时,线程从阻塞态唤醒也是比较耗时的)

自旋锁:如果拿不到锁,不会马上进入阻塞状态,而是等待一段时间(类似于线程在那里做空循环),如果循环一定的次数,还是拿不到锁,那么它立即进入阻塞状态。

自适应自旋锁:普通的自旋锁每个线程循环等待的时间是一样的,由用户指定。而自适应自旋锁本身能够判断需要循环的次数,而且不同线程可能的循环次数也可能不一样。其原理是:如果一个线程在前不久拿到过这个锁,或者它之前经常拿到这个锁,那么我们可以认为,它再次拿到这个锁的概率非常大,所以循环次数会多一些。反之,则循环次数少一些。

上面这三种锁,都是悲观锁

轻量级锁
进入的时候,不加锁,只需要做一个状态标记就好。如果未被其它线程标记,则进入执行。采用CAS来改变状态比加锁花销小很多。如果遇到有竞争,则将轻量级锁升级为重量级锁。

偏向锁
如果这个方法没人进来过,那么一个线程首次进入某个方法时,会采用CAS机制加标记,并会把线程ID也记录进去。让后线程退出时,不改变这个标记(它认为除了自己外,其它线程不会执行这个方法)。然后,线程下次进入这个方法的时候,如果,标记的线程ID是自己的,那么它就直接进入这个方法执行。如果线程ID不是自己的,则将偏向锁升级为轻量级锁。

上面这两种锁是乐观锁

共享锁:也称读锁,允许多个连接在同一时刻并发的读取同一资源,互不干扰。
排它锁:也称写锁。一个写锁会阻塞其它写锁或读锁,防止其它用户对该数据的读写。

码字很辛苦,转载请注明来自胡伟的博客《关于锁的知识的总结》

评论