Java并发编程 之 乐观锁和悲观锁

悲观锁

可以把悲观锁想成一个很小心的人,无论做什么操作之前,都要去加个锁,这样别人想拿这个数据就会block直到它拿到锁。但是在效率方面,处理加锁的机制会产生额外的开销,还有增加产生死锁的机会。另外如果只有只读事物,这个锁是没必要的。
传统的关系型数据库里边就用到了很多这种锁机制,比如读锁,写锁等,都是在做操作之前先上锁。

悲观锁的实现

在java中,synchronized就是一种悲观锁的实现。这个很好理解,采用独占的方式来访问,每次访问都需要获取锁才可以继续进行。

乐观锁

乐观锁相较于悲观时就“乐观”多了,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。

乐观锁不能解决脏读的问题。例如:用户A,B看到的值都是6,用户B把值改为2,用户A读到的值仍为6。

乐观锁的实现

CAS是项乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。

在JDK1.5 中新增java.util.concurrent(J.U.C)就是建立在CAS(compare and swap)之上的。我们以java.util.concurrent中的AtomicInteger为例,看一下在不使用锁的情况下是如何保证线程安全的。主要理解getAndIncrement方法,该方法的作用相当于 ++i 操作。

getAndIncrement采用了CAS操作,每次从内存中读取数据然后将此数据和+1后的结果进行CAS操作,如果成功就返回结果,否则重试直到成功为止。而compareAndSet利用JNI来完成CPU指令的操作。
还是不理解CAS的,点击这里看实例

乐观锁和悲观锁适用场景

像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。

    原文作者:java锁
    原文地址: https://blog.csdn.net/makecontral/article/details/78407891
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞