【锁策略+CAS+synchronized】

一.常见锁策略

策略,和普通程序猿基本没啥关系,和"实现锁"的人才有关系。

这里锁提到的“锁策略”,和JAVA本身没有关系,适用于所有和“锁”相关的情况。

1.悲观锁 VS 乐观锁 (处理锁冲突的态度

悲观锁:预期锁冲突的概率很高。做的工作更多,付出的成本更多,更低效~

乐观锁:预期锁冲突的概率很低。 做的工作更少,付出的成本更低,更高效~

 2.读写锁 VS 普通的互斥锁

对于普通的互斥锁,只有两个操作,加锁和解锁,只要有两个线程针对同一个对象加锁,就会产生互斥~~

对于读写锁来说,分为三个操作:

加读锁:进行读操作,就加读锁

加写锁:进行修改操作,就加写锁

解锁

读锁和读锁之间,是不存在互斥关系的,读锁和写锁之间、写锁和写锁之间,才需要互斥~

3.重量级锁 VS 轻量级锁(处理锁冲突的结果)

和悲观乐观锁有一定重叠

重量级锁,就是做更多的事情,开销更大。

轻量级锁,就是做的事情更少,开销更小。

也可以认为,通常情况下(不绝对):悲观锁一般都是重量级锁;乐观锁一般都是轻量级锁。

在使用的锁中,如果锁是基于内核的一些功能来实现的(比如调用了操作系统提供的mutex接口),此时一般认为这是重量级锁。(操作系统的锁会在内核中做很多事情,比如让线程阻塞等待)。

如果锁是纯用户态实现的,此时一般认为这是轻量级锁.(用户态的代码更可控,也更高效)。

 4.挂起等待锁 VS 自旋锁

挂起等待锁,往往就是通过内核的一些机制来实现,往往较重。【重量级锁的一种典型实现】

自旋锁,往往就是通过用户态代码来实现,往往较轻。【轻量级锁的一种典型实现】

5.公平锁 VS 非公平锁

公平锁:多个线程在等待一把锁的时候,谁是先来的(谁是第一个来等待的),谁就能先获取到这个锁。(遵守先来后到)

非公平锁:多个线程在等待一把锁的时候,不遵守先来后到。(每个等待的线程获取到锁的概率都是均等的)

操作系统提供的mutex这个锁,就是属于非公平锁。

要想实现公平锁,反而要付出更多的代价。(整个队列,把这些参与竞争的线程排一排先来后到)

 6.可重入锁 VS 不可重入锁

一个线程,针对一把锁,连续加锁两次,如果会死锁,就是不可重入锁,如果不会死锁,就是可重入锁。

二、synchronized(关于上述锁策略)

1.既是一个乐观锁,又是一个悲观锁。(根据锁竞争的激烈程度,自适应)

2.不是读写锁,只是一个普通互斥锁

3.既是一个轻量级锁,也是一个重量级锁(根据锁竞争的激烈程度,自适应)

4.轻量级锁的部分基于自旋锁来实现,重量级锁的部分基于挂起等待锁来实现

5.非公平锁

6.可重入锁

三、CAS(compare and swap)

要做的事,拿着寄存器/某个内存中的值和另外一个内存的值进行比较,如果值相同了,就把另一个寄存器/内存的值,和当前的这个内存进行交换~

 此处所谓的CAS指的是CPU提供了一个单独的CAS指令,通过这一条指令,就完成上述伪代码描述的过程~~如果上述过程都是这“一条指令”就干完了,就相当于这是原子性的操作了

CAS最大的意义,就是让我们写这种多线程安全的代码,提供了一个新的思路和方向。(和锁不一样)

CAS都能干啥???

1.基于CAS能够实现“原子类”

(java标准库里提供了一组原子类,针对所常用多一些int、long、int array....进行了封装,可以基于CAS的方式进行修改,并且线程安全)

    public static void main(String[] args) throws InterruptedException {
        AtomicInteger num = new AtomicInteger(0);
        Thread t1 = new Thread(() ->{
            for (int i = 0; i < 5000; i++) {
                num.getAndIncrement();
            }
        });
        Thread t2 = new Thread(() ->{
            for (int i = 0; i < 5000; i++) {
                num.getAndIncrement();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        //通过get方法得到原子类内部的数值
        System.out.println(num.get());
    }

 

 这个代码里面不存在线程安全问题.

基于CAS实现的++操作.这里面就可以既能够线程安全,又能够比synchronized高效,synchronized会涉及到锁的竞争,两个线程要相互等待。CAS不涉及到线程阻塞等待~

 为啥上述实现的++操作是线程安全的?

 CAS既完成了判定,又完成了赋值~

CAS是执行了比较,+1,交换这三个动作~~

2.基于CAS能够实现“自旋锁”

3.CAS中的ABA问题

CAS中的关键,是先比较,再交换~

比较其实是在比较当前值和旧值是不是相同,把这两个值相同就视为中间没有发生过改变~

但是上述结论存在漏洞,当前值和旧值可能是中间确实没改变过,也有可能变了,但是又变回来了~

ABA问题产生BUG的例子:

 

 

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值