常见的策略锁(锁的类型)

  1. 乐观锁
    乐观锁假设认为数据一般情况下不会产生冲突,所以在数据进行提交更新时,才会正式对数据是否产生并发冲突进行检测,如果发现并发冲突了,则让用户返回错误的信息,让用户决定如何去做。
    乐观的心态看待线程安全问题,字节修改共享变量,基于某些机制,要么直接修改成功(没有冲突),要么修改失败(通过返回值可以知道,一般是Boolean)。不管成功还是失败,自行决定下一步怎么做(Java程序层面看,是非阻塞式的方式)

  2. 悲观锁
    总是假设最坏的情况,每次去拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。
    悲观的心态看待线程安全问题,每次都要申请加锁,如果加锁失败,则阻塞。

  3. CAS机制
    Compare and Swap:比较并交换,属于乐观锁的一种实现方式,从Java代码层面看,属于无锁操作。
    CAS比较交换的过程可以通俗理解为CAS(V,O,N),包含三个值分别为:V内存地址存放的实际值,O预期值(旧值),N更新的新值。
    CAS原理
    CAS可能存在的ABA问题:因为CAS会检查就值有没有变化,这里存在这样的问题。比如一个就值A变为了B,然后再变成A,刚好在做CAS时检查发现就值并没有发生变化依然为A,但实际上确实发生变化了。

解决方案:可以沿袭数据库中常用的乐观锁方式,添加一个版本号可以解决。在JDK1.5后的atomic包中提供了AtomicStampeReference来解决问题。

解决原理:Java的CAS利用的是unsafe这个类提供的CAS操作,基于CPU的硬件指令

  1. 自旋锁
    基于CAS操作变量时,如果出现CAS修改失败,可以使用自旋的方式,再次尝试:使用CAS再次修改自旋就是指在CAS失败时,不停的循环CAS操作。

优缺点:
自旋操作,本身还是线程的运行态执行代码,会占据一定的系统资源

使用场景:
(1)大多数场景下,在同一个时间点,常常只有一个线程对变量操作(CAS的场景)
(2)CAS的执行时间,不能太长,否则线程冲突的几率会很大,进一步导致CAS操作失败的线程浪费较多的系统资源。

  1. synchronized同步锁
    作用:对对象头加锁的方式,保证线程安全,多线程申请同一把锁,会产生同步互斥的作用

原理:
(1)synchronized基于系统的mutex lock,就属于悲观锁
(2)该关键字会编译为字节码1个monitiorenter+多个monitorexit指令(多个的目的,是正常执行和异常执行都要释放锁)
(3)对对象头加锁,有偏向锁、轻量级锁、重量级锁(从低到高),三种状态,只能升级不能降级

重量级锁:大多数情况下,在同一时间点,常常有多个线程竞争同一把锁,悲观锁的方式,竞争失败的线程会不停的在阻塞及被唤醒态之间切换,代价比较大

轻量级锁:大多数情况下,在同一个时间点常常只有一个线程竞争对象锁,乐观锁CAS的实现

偏向锁:同一个线程,重入的方式,多次申请同一把锁。

  1. 死锁
    产生条件:多个线程申请资源,持有锁的线程还没有释放锁的情况下,再次申请其他线程始终不释放的锁。结果就造成了死锁的线程始终处于阻塞状态,任务一直无法执行。

检测手段:
jconsole:检测死锁
jstack

  1. volatile
    作用:
    (1)禁止指令重排序
    (2)建立内存屏障,禁止指令重排序

原理:
(1)如何保证可见性?
总线嗅探技术:基于volatile修饰的变量,如果某个CPU修改变量值,其他CPU就会马上得到通知
缓存一致协议:读取时,CPU缓存值置为无效,从主存读写回主存,发起通知。

(2)如何禁止指令重排序?
指令重排序,有as-if-serial的规范,规定了如何重排序(单线程下,前后关联的不能重排序),但不保证多线程下,指令之间的重排序
字节码层面看:提供主存到工作内存,读写操作的8大原子性指令,这些指令存在happens-before的原则

  • 程序顺序规则:一个线程的每个操作,happens-before于该线程中的任意后序操作
  • 监视器规则:对一个锁的解锁,happens-before于随后对这个锁的加锁
  • volatile变量规则:对于一个volatile域的写,happens-before于任意后序对这个volatile域的读
  • 传递性:如果A happens-before B,且B happens-before C,那么A happens-before C
  •  CPU层面看:
     使用volatile修改的变量操作,CPU指令(汇编)是lock前缀指令
    
  • 变量值写回主存时,之前的操作都需要完成
  • 加锁属于总线锁/高速缓存锁
  • 加锁其实就类似于建立了一个屏障:写回主存,之前的都完成,之后的读操作,必须等写操作完成(读、写不能重排序)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值