首页 > 其他 > 详细

synchronized,volatile

时间:2021-01-13 09:05:37      阅读:31      评论:0      收藏:0      [点我收藏+]

sychronized:JDK早期,synchronized 叫做重量级锁, 因为申请锁资源必须通过kernel, 系统调用。后面对其进行了优化。

较早的版本,OS的资源 互斥量 用户态 -> 内核态的转换 重量级 效率比较低

现代版本,无锁 - 偏向锁 -轻量级锁(自旋锁)-重量级锁

CAS

Compare And Swap(Compare And Exchange) / 自旋 / 自旋锁 / 无锁 (无重量锁)

cas(v, a, b) ,变量v,期待值a, 修改值b。ABA问题,即原值是A,修改后为B,之后又改为A,导致CAS无法判断A的值是否发生过改变。解决办法(版本号 AtomicStampedReference),基础类型简单值不需要版本号。

最终实现;lock cmpxchg 指令。

 

创建一个对象----默认有偏向锁----如果有其它线程竞争会转为轻量级锁----重度竞争使用重量级锁

JVM启动过程,默认情况启动时不打开偏向锁,过一段儿时间再打开,因为JVM虚拟机自己有一些默认启动的线程,里面有好多sync代码,这些sync代码启动时就知道肯定会有竞争,如果使用偏向锁,就会造成偏向锁不断的进行锁撤销和锁升级的操作,效率较低。

 

自旋锁什么时候升级为重量级锁?为什么有自旋锁还需要重量级锁?

自旋是消耗CPU资源的,如果锁的时间长,或者自旋线程多,CPU会被大量消耗。重量级锁有等待队列,所有拿不到锁的进入等待队列,不需要消耗CPU资源

偏向锁是否一定比自旋锁效率高?

不一定,在明确知道会有多线程竞争的情况下,偏向锁肯定会涉及锁撤销,这时候直接使用自旋锁。

 

我们知道创建的对象存放在堆中,但一个对象又包括哪些部分呢?简单来说可以分为:对象头(mark word,klass word,数组长度【可选】),对象体(对象的属性值),对齐字节。

对象的几个部分的作用:

1.对象头中的Mark Word(标记字)占8个字节,主要用来表示对象的线程锁状态,另外还可以用来配合GC、存放该对象的hashCode;

2.Klass Word是一个指向方法区中Class信息的指针,意味着该对象可随时知道自己是哪个Class的实例;

3.数组长度也是占用64位(8字节)的空间,这是可选的,只有当本对象是一个数组对象时才会有这个部分;

4.对象体是用于保存对象属性和值的主体部分,占用内存空间取决于对象的属性数量和类型;

5.对齐字是为了减少堆内存的碎片空间(不一定准确)。

技术分享图片

偏向锁 - markword 上记录当前线程指针,下次同一个线程加锁的时候,不需要争用,只需要判断线程指针是否同一个,所以,偏向锁,偏向加锁的第一个线程 。hashCode备份在线程栈上 线程销毁,锁降级为无锁。

有争用 - 锁升级为轻量级锁 - 每个线程有自己的LockRecord在自己的线程栈上,用CAS去争用markword的LR的指针,指针指向哪个线程的LR,哪个线程就拥有锁。

自旋超过10次,升级为重量级锁 - 如果太多线程自旋 CPU消耗过大,不如升级为重量级锁,进入等待队列(不消耗CPU)-XX:PreBlockSpin

自旋锁在 JDK1.4.2 中引入,使用 -XX:+UseSpinning 来开启。JDK 6 中变为默认开启,并且引入了自适应的自旋锁(适应性自旋锁)。

自适应自旋锁意味着自旋的时间(次数)不再固定,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也是很有可能再次成功,进而它将允许自旋等待持续相对更长的时间。如果对于某个锁,自旋很少成功获得过,那在以后尝试获取这个锁时将可能省略掉自旋过程,直接阻塞线程,避免浪费处理器资源。

偏向锁由于有锁撤销的过程revoke,会消耗系统资源,所以,在锁争用特别激烈的时候,用偏向锁未必效率高。还不如直接使用轻量级锁。

synchronized,volatile

原文:https://www.cnblogs.com/chigejuzhi/p/14270076.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!