悲观锁和乐观锁
悲观锁
悲观锁是总会先去想最坏的情况,每次线程拿数据的时候都会认为他会进行修改,适用于的场景是多写少读,这时使用悲观锁效率会高。程序中典型的悲观锁时synchronized和ReentrantLock
乐观锁
乐观锁是总会先去想好的情况,每次线程拿数据只会看一眼,并不会做修改操作,这时没有必要加锁,程序中的atom原子类使用cas+volatile+native方法实现乐观锁。
两种锁的机制,有各自的好处,不能说谁好谁坏,各有优点:
悲观锁适用于多写少读的情况,而乐观锁适用于多读少写的情况,如果在多写的情况下使用乐观锁,会经常产生冲突,反而会降低性能。
乐观锁常用的两种方式
版本号的控制
每次读取数据的时候都会连同版本号一同读取,在当更新数据的时候,会比较读取到的版本号和数据库中的版本号是否一致,如果一致则更新,如果不一致则继续读取,更新数据。
CAS操作(compareAndSwap)
举个例子,在atomInteger类中涉及了CAS
1 | public final native boolean compareAndSwapInt(Object o, long offset, |
比较替换(compareAndSwap)
是一个原子操作,也是一个自旋操作,等待一个周期再次尝试。
CAS操作的缺点
- ABA问题,何谓ABA:当两个线程读取到当前值为A,其中一个线程把值改为B后再把B改为A,这是另外一个线程使用cas操作读取到的值仍然是A,CAS会认为这个值从来没有变过,这就是ABA问题。也就是说遗失掉中间的过程,在链式的操作总更能体会到ABA问题的严重性。
- 自旋时间过长,消耗CPU资源。
- 只能对单个共享变量的原子性操作