2.CAS与锁相关

1. Java锁的分类

(1)悲观锁与乐观锁
(2)公平锁与非公平锁
(3)自旋锁与重入锁
(4)重量级锁与轻量级锁
(5)独占锁与共享锁

2.悲观锁与乐观锁

什么是悲观锁

在Mysql数据库修改一行数据就是悲观锁,悲观锁就是比较悲观,当多个线程对同一行数据进行修改的时候,最后只有一个线程能够修改成功,只要谁能够获取到行锁,则其他线程都不能对该数据进行修改,且是阻塞状态。
在Java角度,悲观锁如果没有获取到锁,则会阻塞等待,唤醒锁的成本较高。
在java中,Lock 和 synchronize锁都是悲观锁。

乐观锁

乐观锁比较乐观,认为不会有其他线程修改数据,通过预期或者版本号比较,如果不一致的情况则通过循环控制修改,线程不会被阻塞,效率较高。但是会消耗CPU资源。

Mysql层面实现乐观锁

(1)在表字段中增加一个version字段
(2)多个线程对同一行数据实现修改操作时,提前获取当前的version作为更新的判断依据
(3)带着verison编号去执行更新操作,如果version变了则修改失败
(4)修改失败就不断重试,直到成功

3.公平锁与非公平锁

公平锁

就是比较公平,根据请求锁的顺序排队,先来请求的线程就先获取锁,后来的就后获取,采用队列进行存放, 类似于吃饭排队,打水排队。

公平锁示例:

    public static void main(String[] args) {
    	//通过 ReentrantLock 创建一个公平锁,根据参数传递 true
        ReentrantLock reentrantLock = new ReentrantLock(true);
        //创建10个线程测试这个 获取锁的过程
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            new Thread(() -> {
                try {
                    reentrantLock.lock();
                    System.out.println(Thread.currentThread().getName() + "--" + finalI);
                } catch (Exception e) {

                } finally {
                    if (reentrantLock != null) {
                        reentrantLock.unlock();
                    }
                }

            }).start();
        }
    }
}

运行结果:可以看到,获取锁的线程是有顺序的
在这里插入图片描述

非公平锁

顾名思义,不是根据请求顺序排列的,通过争抢的方式获取锁,哪个线程进来都先看一眼锁在不在,在就获取,不在再去排队等着抢。

非公平锁的效率比公平锁的效率要高,synchronized是非公平锁

非公平锁的示例:只需要把上述代码改成 false

    public static void main(String[] args) {
        ReentrantLock reentrantLock = new ReentrantLock(true);
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            new Thread(() -> {
                try {
                    reentrantLock.lock();
                    System.out.println(Thread.currentThread().getName() + "--" + finalI);
                } catch (Exception e) {

                } finally {
                    if (reentrantLock != null) {
                        reentrantLock.unlock();
                    }
                }

            }).start();
        }
    }
}

运行结果:可以看到线程无序
在这里插入图片描述

公平锁的底层是如何实现的

通过队列的方式去实现 线程获取锁的排队,根据顺序去获取锁并执行逻辑。

4.锁的可重入性与自旋锁

什么是锁的可重入性

在同一个线程中锁是可以不断传递的,可以直接获取。

比如递归、A调用B这种情况,不可能等A把锁释放了再调用B吧,因为B是A方法的一部分,A也没有运行完。所以锁是线程级别的,它会记录是哪个线程获取了这个锁,然后那个线程就可以直接用这个锁去对应的方法直接用。

例如 synchronized、lock、aqs。

什么是CAS

CAS:Compare And Swap ,比较并交换,执行函数CAS(V,E,N)

CAS不是Java实现的,是由JNI调用C++实现的。

通常来讲,锁的存在导致 没有获取到锁的线程 会阻塞,为了解决这个问题,CAS的存在让线程不再阻塞,而是靠着一直自旋(循环运行)。

CAS的运行逻辑

CAS有三个操作数 ,内存值V(共享值),旧的期望值E(读取到的共享值),要修改的新值N
当且仅当预期值与内存值相同时,将内存值V修改为N,否则什么都不做,这个概念其实与乐观锁的类似。
当 E==V时,才会改变V。

CAS的优缺点

优点:通过循环的方式解决了 线程因为锁阻塞的问题
缺点:循环次数过高的话,会导致CPU标高,所以需要控制次数。

ABA问题

通过以上可以知道, 比较V和E时,我们如何知道 即使V值 和E 相同,但是已经变过了呢??

一般可以增加一个版本号version

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值