悲观锁与乐观锁
悲观锁
总是假设最坏的情况,每次取数据的时候都认为别人会来修改,所以每次取数据的时候都会上锁。其它线程想要取这份数据就必须拿到相应的锁(共享资源每次只供一个线程使用,其它线程阻塞,用完之后转让给其他线程)。
传统关系型数据库里有很多悲观锁的实现,如行锁、表锁、读写锁。Java中的synchronized和ReetrantLock 等独占锁就是悲观锁的实现。
MySQL InnoDB中使用悲观锁
要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。
set autocommit=0;
select…for update
使用select…for update会把数据给锁住,不过我们需要注意一些锁的级别,MySQL
InnoDB默认行级锁。行级锁都是基于索引的,如果一条SQL语句不用索引会使用表级锁把整张表锁住,这点需要注意。
悲观锁机制存在以下问题:
-
在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题。
-
一个线程持有锁会导致其它所有需要此锁的线程挂起。
-
假如一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险。
乐观锁
总是假设最好的情况,每次取数据时都认为别人不会修改,所以不会上锁,但是在更新的时候会先判断在此期间是否有别的线程更新这份数据(通过版本号机制或CAS算法实现)。乐观锁用于多读少写的场景,这样能够提高吞吐量
java.util.concurrent.atomic包下面的原子变量类就是通过乐观锁的CAS方式来实现的。
CAS算法见我之前的博文。
上一篇: 乐观锁
下一篇: .Net开发WinCE应用程序杂碎(转)