synchronized终极原理-学习

http://www.cnblogs.com/dennyzhangdd/p/6734638.html 

这个在这个博文学习的。ε=(・д・`*)ハァ…有的看不懂。

我的理解,不对可以喷。不过估计没人看。

synchronized的加锁机制由原来的普遍重型锁变成了锁升级无锁---》偏向锁---》轻型锁---》重型锁。

HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。 

HotSpot虚拟机的对象头(Object Header)包括两部分信息:
第一部分"Mark Word":用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等.
第二部分"Klass Pointer":对象指向它的类的元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。(数组,对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中无法确定数组的大小。 ) 

改变后的优点:

第一步,检查MarkWord里面是不是放的自己的ThreadId ,如果是,表示当前线程是处于 “偏向锁”.跳过轻量级锁直接执行同步体。
第二步,如果MarkWord不是自己的ThreadId,锁升级,这时候,用CAS来执行切换,新的线程根据MarkWord里面现有的ThreadId,通知之前线程暂停,之前线程将Markword的内容置为空。
第三步,两个线程都把对象的HashCode复制到自己新建的用于存储锁的记录空间,接着开始通过CAS操作,把共享对象的MarKword的内容修改为自己新建的记录空间的地址的方式竞争MarkWord.
第四步,第三步中成功执行CAS的获得资源,失败的则进入自旋.
第五步,自旋的线程在自旋过程中,成功获得资源(即之前获的资源的线程执行完成并释放了共享资源),则整个状态依然处于轻量级锁的状态,如果自旋失败 。
第六步,进入重量级锁的状态,这个时候,自旋的线程进行阻塞,等待之前线程执行完成并唤醒自己.


线程1访问同步代码块。检查这个代码块的对象的对象头中是否有线程1的线程id,如果没有进行cas操作将自己的线程id写入到对象头中。这个时候对象头的结构已经发生变化了。操作成功就将对象头中线程id指向当前线程1,这个时候已经从无锁状态转换为偏移锁状态。假如线程1在执行同步体过程中有其他线程对同步代码块的对象头进行cas操作将线程id写入,此时操作肯定失败。就要撤销偏向锁暂停线程。解除偏向锁将线程id设置为空。恢复线程将锁升级。

线程1、线程2将同步代码块的对像头复制到线程私有的栈空间。同时将栈中的对象头信息通过cas操作将内存中的对象头进行更新。只会有一个更新操作会成功,成功的线程会获得这个对象的锁资源。假如如图所示线程1会获得轻量级锁。而此时线程2更新内存中对象头失败后会自旋获取锁,间隔一段时间执行一次将本栈中线程对象头更新到内存中的操作。系统默认为10次,如果10次后没有拿到过锁的资源。轻量级锁膨胀改为重量级锁,线程2阻塞。线程1在对主内存中对象头进行更新时会失败,释放锁。线程1会执行完毕后唤醒线程2。

本文重点介绍了Synchronized原理以及JVM对Synchronized的优化。简单来说解决三种场景:

1)只有一个线程进入临界区,偏向锁

2)多个线程交替进入临界区,轻量级锁

3)多线程同时进入临界区,重量级锁


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值