一、分别是什么?
1、乐观锁
乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,就算改了也没关系,所以不会上锁。但是在更新的时候会判断一下在此期间别人有没有去修改这个数据,如何没有人修改则更新,如果有人修改则重试。
乐观锁的实现:
- CAS(Compare and Swap)实现:Java中java.util.concurrent.atomic包下面的原子变量使用了乐观锁的一种CAS实现方式。
2、悲观锁
悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会block直到拿到锁。
悲观锁的实现:
- 传统的关系型数据库使用这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
- Java里面的同步synchronized关键字、以及JDK中的ReentrantLock都是悲观锁的实现
二、如何选择?
两种锁各有优缺点,不能单纯的定义哪个好于哪个。
乐观锁比较适合读取比较频繁、数据修改比较少的场景,即使出现了少量的修改冲突,这样也省去了大量的锁的开销,故而提高了系统的吞吐量。但是如果经常发生冲突(数据修改比较频繁的情况下),触发上层应用不断的重试,这样反而浪费了开销,降低了性能,对于这种情况使用悲观锁就更合适。
- 1、响应效率:如果需要非常高的响应速度,建议采用乐观锁方案,不需要等待其他并发去释放锁。
- 2、冲突频率:如果冲突频率非常高,建议采用悲观锁,保证成功率。冲突频率大,选择乐观锁会需要多次重试才能成功,代价比较大。
- 3、重试代价:如果重试代价大,建议采用悲观锁。