synchronized底层实现
1、锁升级的过程
当多个线程同时竞争一个对象监视器时:当前对象结构中的mark word中是否是当前线程id,如果是则当前线程获得偏向锁。
如果不是,则通过CAS将当前线程id置换到mark word中,如果成功则获得偏向锁,如果不成功则说明有竞争,升级为轻量级锁。
后续再通过CAS将线程的指针放到mark word中,若成功则获得锁,否则升级为自旋锁。自旋锁仍然为轻量级锁,不成功升级为重量级锁。
对象结构:在JVM中,对象在内存中的布局分为三块区域:对象头、实例数据和对齐填充
mark word:存在于对象头中,存储对象的hashcode,锁标识,分代年龄及GC标识等信息
由上图可以看出,为何偏向锁是将线程id放入mark word,轻量级锁为何将锁的指针放入mark word。
偏向锁:指偏向于第一个访问的线程,在运行过程中,同步锁没有竞争,则会在这个线程的头部加一个标志位,标记为偏向锁,如果发生竞争则会升级为轻量级锁或者重量级锁
自旋锁:线程请求不到对象锁时不会堵塞,只是自己循环一下等待对象锁的释放。因为线程的堵塞和唤醒非常消耗内存,所以自旋锁可以很好的优化这个问题。
但它只适合等待时间比较短的,而且并发量不高的场景。
2、升级到重量级锁后,如何运行
当多线程竞争时,不满足的条件的线程会进入同步队列,满足条件后进入同步代码。在同步代码中执行wait方法,释放对象锁,进入右侧等待队列,当唤醒时 还需要再次获得互斥锁。
synchronized结构:
Contention List:竞争队列,所有请求锁的线程首先被放在这个竞争队列中;
Entry List:Contention List中那些有资格成为候选资源的线程被移动到Entry List中;
Wait Set:哪些调用wait方法被阻塞的线程被放置在这里;
OnDeck:任意时刻,最多只有一个线程正在竞争锁资源,该线程被成为OnDeck;
Owner:当前已经获取到所资源的线程被称为Owner;
大量并发线程会在contention List中,然后将有资格成为候选的放到entry list中。调用的wait的线程放到wait set中,当被唤醒后会放到entry list中。
指定EntryList中的某个线程为OnDeck线程(一般是最先进去的那个线程),然后onedeck线程去竞争锁,但是此时其他未进入contention list的线程会先自旋一下看是否能获得到锁,
所以说synchronied不是公平的。
当使用synchronized加类锁时,会有严重的效率问题,此时需要考虑是否可以修改为细粒度锁,当修改细粒度锁时,要避免死锁。
上述若有不对,麻烦各位指正
最新文章
- windows xp 连接USB网络打印机服务器(通用所有usb网络打印机服务器的安装)
- 1.go的Hello
- WORD 粘贴代码 不检查语法
- eclipse下mysql编程
- UML Distilled - Development Process
- PreferenceFragment界面透明问题
- Apache虚拟主机的配置
- Ext.MessageBox.Show使用Progress
- 取消a标签的页面跳转
- JDK源码阅读(1)_简介+ java.io
- awk匹配以aaa开头,以bbb结尾的内容,同时aaa和bbb之间还包含ccc
- java创建线程的几种方式,了解一下
- java 11 值得关注的新特性
- piwik高负载加速之切换session存储位置
- 在Docker Swarm上部署Apache Storm:第2部分
- mysql性能监控qps,tps,iops
- MySQL(4):主从复制原理
- iOS 绘图 (UIImage的一些操作)
- 在android studio中集成javah, ndk-build进行JNI开发
- 20190401-记录一次bug ConstraintViolationException