悲观锁&乐观锁

@[toc]

锁都分类

悲观锁&乐观锁

什么是悲观锁,乐观锁

乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展。这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人。

悲观锁

总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。

如图所示 ,synchronized 就是悲观锁都一个实现思路,如下代码,
每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁

private Object object =new Object();
    
    public void sale(){
        synchronized (object){
            if(count > 0){
                System.out.println(Thread.currentThread().getName() +"出售 :" +(100 - count + 1));
                count--;
            }
        }
    }

乐观锁

总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

以 java.util.concurrent 中的 AtomicInteger 为例

AtomicInteger 内部使用 cas无锁机制,不会进行加锁, 但是在更新的时候会判断一下在此期间别人有没有去更新这个数据

package com.dimple.test;

import java.util.concurrent.atomic.AtomicInteger;

public class Test5 {


    public static void main(String[] args) {

        TestDemo thread = new TestDemo();
        Thread t1 = new Thread(thread,"窗口一");
        Thread t2 = new Thread(thread,"窗口二");
        t1.start();
        t2.start();
    }
}

class TestDemo implements Runnable{
    //共享的火车票变量
    private static AtomicInteger atomic = new AtomicInteger(100);

    //重寫run方法
    @Override
    public void run() {
        while (atomic.get() > 0){
            try {
                //休眠一下 方便出现并发问题
                Thread.sleep(50);
            }catch (Exception e){
                e.getMessage();
            }

            sale();
        }
    }
    //卖票
    public void sale(){

        if(atomic.get() > 0){
          Integer count=  100 - atomic.getAndDecrement() + 1; //使用底层方法getAndDecrement()  自-1;
            System.out.println(Thread.currentThread().getName()+ "," + count);//获取当前值
        }


    }

}

经典案例

  • git 版本控制工具 典型都乐观锁实现思路,当我们往远程仓库 push的时候 ,git 会检查我们的版本是否落后于版本库的版本,如果落后,push就会报错,如果一致,就提交成功
  • git 不适用于悲观锁,否则 公司倒闭

开销对比

悲观锁的开销肯定要大于乐观锁,但是特点一劳永逸,乐观锁 始终无锁机制,比对版本号,性能要优于 悲观锁,
悲观锁&乐观锁

上一篇:自旋锁与阻塞锁


下一篇:Elasticsearch入门-1