Java并发锁(一):悲观锁与乐观锁

本文是粉丝投稿,原文地址:https://blog.csdn.net/qq_33540203/article/details/92597837java

今天咱们来聊下线程中的悲观锁和乐观锁,首先提到"悲观锁","乐观锁"提到这两个名词,你们可能会先想到数据库。注意啦,咱们这里讲的是多线程中的锁,而不是数据库中的锁(没听过的童鞋,能够百度了解下。大概思想同线程中的悲乐锁思想差很少)。在Java中,经常使用Api提供的锁就是synchronized和lock,以及CAS。不知道你们有没有这样的疑惑,我什么场景下用哪把锁最为合适。算法

synchronized和Lock都是悲观锁,它们认为当使用数据的时候必定有其它线程来修改,因此在获取数据的时候就会加锁,确保不会被其它线程修改。数据库

synchronized代码块:微信

public synchronized void update() { //同步资源    }

Lock代码块:多线程

public void update() { Lock lock = new ReentrantLock(); lock.lock(); try { //同步资源 } finally { lock.unlock(); }    }

乐观锁,它认为使用数据的时候不会有别的线程来修改数据,因此不会加锁。只要在自身要进行update操做的时候,才会去判断以前的数据是否被别的线程修改了。若是没有被修改则会修改为功,相反则会修改不成功。这里最典型的是java.util.concurrent并发包中的递增操做就经过CAS自旋实现的。并发

CAS代码块app

public class TestLock {  AtomicInteger atomicInteger = new AtomicInteger(0);  public int add() { return atomicInteger.incrementAndGet(); }}

什么是CAS,CAS的全称为Compare And Swap(比较与交换),是一种无锁算法。在不使用锁(没有线程被阻塞)的状况下实现多线程之间的变量同步。性能

总结: 这里咱们能够得出悲观锁适合写操做多的场景,先加锁能够保证写操做时数据正确。乐观锁适合读操做多的场景,不加锁的特色可以使其读操做的性能大幅提高。不过从jdk1.8以后java已经对synchronized作了优化,性能上有了大幅度的提高。可是乐观锁CAS,也不是那么十全十美,目前它存在三个三大问题。大数据

  1. ABA问题(JDK1.5以后已有解决方案):CAS须要在操做值的时候检查内存值是否发生变化,没有发生变化才会更新内存值。可是若是内存值原来是A,后来变成了B,而后又变成了A,那么CAS进行检查时会发现值没有发生变化,可是其实是有变化的。ABA问题的解决思路就是在变量前面添加版本号,每次变量更新的时候都把版本号加一,这样变化过程就从“A-B-A”变成了“1A-2B-3A”。优化

  2. 循环时间长开销大:CAS操做若是长时间不成功,会致使其一直自旋,给CPU带来很是大的开销。

  3. 只能保证一个共享变量的原子操做(JDK1.5以后已有解决方案):对一个共享变量执行操做时,CAS可以保证原子操做,可是对多个共享变量操做时,CAS是没法保证操做的原子性的。

     你们能够把1和3的解决方案告诉我吗?

也能够点击阅读原文跳转。

本文分享自微信公众号 - 浪尖聊大数据(bigdatatip)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索