多线程---锁策略、CAS、锁的优化

一、常见的锁策略

        锁策略是是指在多线程编程中用于同步资源访问的机制,常见的锁策略有:

        1.乐观锁 和 悲观锁

        乐观锁:假设在一个程序中锁的竞争不大,认为数据一般情况下不会产生并发冲突,因此在操作数据时不对数据加锁,在修改数据的时候才会判定是否发生并发冲突。
        悲观锁:假设一个程序中的锁竞争很大,认为修改数据的时候一般会发生并发冲突,因此
每次在拿到数据的时候都会加上锁,其他线程只能阻塞等待锁。

        2.轻量级锁 和 重量级锁

        轻量级锁:加锁的开销比较
        重量级锁:加锁的开销比较

        3.自旋锁 和 挂起等待锁
        自旋锁:指在锁竞争失败后
不会释放CPU资源,而是立刻尝试在获取锁,一直无限循环直到得到锁
        挂起等待锁:指的的在锁竞争失败后会
阻塞等待释放CPU资源,等到没有线程使用锁的时候再来获取锁。

        4.公平锁 和 非公平锁

        公平锁:指的是在锁竞争中遵守 '先来后到' ,哪个线程先加的锁,当锁释放的时候就那个线程先加锁。
        非公平锁:指的是锁竞争是随机的,
不遵守 '先来后到',当一个线程释放锁之后,哪个线程先获得锁是随机的

        5.可重入锁 和 不可重入锁

        可重入锁:是指允许一个线程对自己加锁多次,当一个线程连续对自己加锁多次,而不会构成死锁。
        不可重入锁:是指
不允许一个线程对自己加锁多次,当一个线程对自己加锁多次,就会导致 '自己把自己锁死' 。

        6.读写锁

        读写锁:是指把锁拆分成 读锁 和 写锁,在多线程中2个线程同时读取同一个数据的时候不会构成线程安全问题,而2个线程同时写入同一个数据或者1个线程读数据,1个线程写数据的时候则会构成线程安全问题。把锁拆分成读写锁,当2个锁都是读锁的时候,线程之间不互斥;当2个线程都是写锁或者1个线程是读锁1个线程是写锁的时候,线程之间互斥,由于互斥会引起线程等待,所以减少互斥就能提高程序效率,读写锁使用与于"频繁读,不频繁写"的场景中

二、CAS

        CAS: 全称Compareandswap,字面意思: '比较并交换',CAS涉及到到操作:假设内存中存储的数据位V,预期的原数值为A,要修改的数值为B。当要修改数值的时候,会先比较 V 与 A 的值,当 V 与 A 的值相等的时候(说明没有别的线程修改过数据)才会让V 与 B 交换 (相当于赋值),否则不做任何操作。当多个线程同时对某个资源进行CAS操作,只能有⼀个线程操作成功,但是并不会阻塞其他线程,其他线程只会收到操作失败的信号。CAS相当于通过一个原子的操作,同时完成"读取内存,比较是否相等,修改内存"这三个步骤

        CAS的实现

        在Java标准库中提供了 java.util.concurrent.atomic 包,里面的类都是基于这种方式来实现的. 典型的就是AtomicInteger类。
        AtomicInteger类事例:

        代码结果: 

        CAS的ABA问题

         ABA问题:假设有两个线程t1 和 t2,有一个变量 num 值为A,当线程t1使用CAS对num进行修改的时候会判定sum里的值是否为A当为A的时候才会进行交换,但是有可能当 t1 在执行的时候,t2把num的值从 A改成B再改成A,这时当 t1 进行比较的时候还是num的值还是A,就会进行交换导致了线程安全问题。
        ABA问题可以通过使用引入版本号来解决,每次修改完数据就让版本号自增,在比较的时候也比较一下版本号,如果版本号一样才进行修改操作。

三、关于锁的优化操作

        1.synchronized的优化过程:

      JVM将synchronized锁分为⽆锁、偏向锁、轻量级锁、重量级锁状态。会根据情况,进行依次升级。
       
偏向锁:用synchronized加锁的时候不会马上加锁,而是会先加上偏向锁,偏向锁不是真的加锁,而是做个标记,记录锁是属于哪个线程,等到出现锁竞争的时候才会真正加上锁。

        2.锁消除

        在Java中编译器和JVM会判断锁是否有作用,如果没作用会把锁优化掉,进行锁消除。
        例如:Java中有些方法或类中有自带的synchronized(
例如StringBuffer)当在单线程模式下使用的时候不存在线程安全问题,这时就不需要synchronized加锁,这时JVM就会进行锁消除。

        3.锁粗化

        ⼀段代码中如果出现多次加锁解锁,编译器 和 JVM会自动动进行锁的粗化
        锁的粒度分为粗和细:

        锁的粒度细说明对一个线程要频繁的加锁和解锁,这时JVM会进行锁粗化的优化。 

 

        
        

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Milliliter___

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值