有关锁的介绍

目录

一、悲观锁和乐观锁

1.悲观锁 

Synchronized

2.乐观锁

CAS中的ABA问题

ABA问题的解决

使用CAS所引起的问题

Atomic


一、悲观锁和乐观锁

1.悲观锁 

总是假设最坏的情况,每次去拿数据的时候都会认为数据会被别人改变,所以每次拿数据是都会加锁,这样别人拿这个数据就会阻塞直到他拿到锁。在java中Synchronized实现也是悲观锁。

悲观锁存在问题:

在多线程竞争下,加锁、释放锁会导致比较锁上下文的切换和调度延时,引起性能问题—个线程持有锁会导致其他线程进入阻塞状态

Synchronized

synchronized用的锁是存在Java对象头里的,如果对象是数组类型,则虚拟机用3个字宽(Word)存储对象头,如果对象是非数组类型,则用2字宽存储对象头。在32位虚拟机中,1字宽等于4字节,即32bit。

1.JVM

在创建一个对象后,在JVM虚拟机( HotSpot )中,对象在Java内存中的存储布局可分为三块:

对象头区域:存放锁信息。对象年龄等信息

实例数据区域:此处存储的是对象真正有效的信息,比如对象中所有字段的内容

对齐填充区域:JVM的实现 HostSpot 规定对象的起始地址必须是8字节的整数倍,换句话来说,现在64位的os 往外读取数据的时候一次性读取64bit 整数倍的数据,也就是8个字节,所以 HotSpot 为了高效读取对象,就做了"对齐",如果一个对象实际占的内存大小不是8byte的整数倍时,就""补位""到 8byte的整数倍。所以对齐填充区域的大小不是固定的。

2.偏向锁:(一个线程)JVM不用和操作系铳协商设置Mutex,它使用CAS操作把线程ID记录到了这个Mark Word当中,修改了标识位,不用操作系统介入这时线程获得了锁,当前线程就拥有这把锁了。可以执行synchronized修饰的代码块。
当线程再次执行到这个synchronized的时候,JVM通过锁对象account的Mark Word判断:“当前线程ID还在,还持有着这个对象的锁,就可以继续进入临界区执行。
这就是偏向锁,在没有别的线程竞争的时候,一直偏向当前线程,当前线程可以一直执行。

3.轻量级锁:(有新的线程进入,偏向锁不能满足)JVM把锁对象account恢复成无锁状态,在当前两线程的栈帧中各自分配了一个空间,叫做Lock Record,把锁对象account的Mark Word在俩线程的栈帧中各自复制了一份,叫做Displaced Mark Word然后当前线程的Lock Record的地址使用CAS放到了Mark Word当中,并且把额标志位改为00,这意味着当前线程也已经获得了这个轻量级的镇了。可以继续进入临界区执行。

4. 重量级锁:(一个线程持有锁,另一个线程自旋多次时)重量级锁需要操作系统的介入,依赖操作系统底层的Miutex Lock。JVM创建了一个monitor对象,把这个对象的地址更新到了Mark word当中。

2.乐观锁

乐观锁认为数据一般不会产生冲突,所以在数据进行提交更新时,才会真正对数据是否产生冲突进行检测,如果发生冲突,返回给用户错误信息,由用户来决定如何做。两个步骤:冲突检测和数据更新。

CAS (compare and set):比较并修改

CAS是乐观锁的技术实现,当多个线程尝试使用CAS同时来更新同一个变量,只有一个线程能够更新的变量值,而其他的线程都会失败,失败的线程并不会被挂起,告知这次竞争失败。可以再次尝试
CAS操作包含三个操作数:
需要读写的内存位置(v)

需要比较的预期原值(A)

拟写入的新值(B)

1、获取内存V的值A
2、判断当前的位置V的值和原值A是否相等。如果相等。(认为没有线程并发处理)直接变更为B
如果不相等(认为有线程并发处理)
1、重新获取当前的位置值
2、继续比较。不相等则继续第一步直至当前V的值和原值相等,修改完。
总结:如果内存位置v的值与原预期值A相匹配,那么处理器就会自动将该位置更新为新值B,否则处理器不做任何处理,重复比较直至相等然后修改。

强调:乐观锁是一种思想,CAS是这种思想的一种实现方法
Java中对CAS支持,在jdk1.5之后新增java.util.concurrent(J.U.C)就是建立CAS基础上,CAS是一种非阻塞的实现,例如:Atomic

CAS中的ABA问题

CAS使用起来能够提高性能,但会引起ABA的问题假如如下事件序列:

  1. 线程1队内次位置V来获取值A
  2. 线程2从内存位置V获取A
  3. 线程2进行一些操作。将B写入到V
  4. 线程2将A写入位置v
  5. 线程1进行CAS操作,发现位置v的值任然为A,操作成功了
  6. 线程1尽管CAS操作成功了,该过程有可能出现问题,对于线程1来说,线程2做的处理就可能丢失了

ABA问题的解决

  1. ABA问题解决思路就是使用版本号,在变量前面追加版本号,每次对变量你进行更新的时候对版本进行加1,对于A->B->A就会变成1A->2B->3A

使用CAS所引起的问题

  1. ABA问题:ABA问题可以使用版本号解决问题

  2. 循环时间开销大:自旋CAS如果长时间不成功,会带来CPU很大的开销。可以给循环次数加上阈值,若达到这个阈值就进入阻塞。

  3. 只能保证一个共享原子的操作。

Atomic

Atomic就是volatile的使用场景,也是CAS的使用场景

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值