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

        今天我们来聊下线程中的悲观锁和乐观锁,首先提到"悲观锁","乐观锁"提到这两个名词,大家可能会先想到数据库。注意啦,我们这里讲的是多线程中的锁,而不是数据库中的锁(没听过的童鞋,可以百度了解下。大概思想同线程中的悲乐锁思想差不多)。在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代码块:

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的解决方案告诉我吗??

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值