乐观锁和悲观锁

 在多线程场景中,为了保证线程安全,因此需要对线程加锁,除了使用synchronized关键字外,还有许多的锁机制。 

常见的锁的类型:

偏向锁、自旋锁、轻量级锁、重量级锁、独占锁、共享锁、公平锁、非公平锁、可重入锁、读写锁。

乐观锁vs悲观锁:
乐观锁和悲观锁只是设计思想上的一个概念。
乐观锁:假设认为数据一般情况下不会产生并发冲突,所以在数据提交的时候才会去对数据检查是否发生了并发冲突。(即在同一时间点只有一个线程对共享变量操作,所以适合乐观的思想)
乐观锁的问题:并不总是能处理所有问题,所以会引入一定的系统复杂度。

悲观锁:总是假设最坏的情况,每次别人拿数据时都会产生并发冲突,都会去上锁。(思想:同一时间点,经常有多个线程对共享变量操作,适合悲观锁)
悲观锁的问题:总是需要竞争锁,进而导致发生线程切换,挂起其他线程;所以性能不高。

所以要使用哪种设计思想,应该根据不用的应用场景来决定。
基于乐观锁实现的机制:CAS机制,又称无锁操作;
CAS: Compare And Swap ,比较并交换
CAS(V,O,N)——>V:内存地址实际存放的实际值;O:预期的旧值; N:要赋值的新值。
乐观锁和悲观锁
可能出现的问题:ABA问题
CAS(V,O,N)中,当V==O时,N可以直接写进V;当N!=O时,不能写入,但当O ==N时,也可能时已经被其他线程修改过,但预期的旧值还是等于主存当时存的值,这就是ABA问题。
解决方案:增加版本号;
作用:每次修改后,版本号+1,通过版本号来观察V是否被修改过。

总结:

1.悲观锁是线程先加锁,后修改变量操作;
2.乐观锁是线程直接尝试修改变量操作,在这个过程中不会发生线程阻塞;
3. CAS的实现原理:基于unsafe来实现,本质上是基于CPU提供的接口保证线程安全修改变量;
4. CAS在java中的应用:
自旋锁:
无条件自旋
有条件自旋:如可中断的自旋(自旋时可以使用线程判断中断标志位后再执行)
自旋+CAS的适用场景:同一时间点,常常只有一个线程操作。
不适用的场景:同一时间点,常常有很多线程操作。
自旋的缺陷:线程一直处于运行状态,占用CPU内存,比较耗费资源。

版权声明:玥玥 发表于 2021-03-24 8:10:46。
转载请注明:乐观锁和悲观锁 | 女黑客导航