java锁

1.java synchronized关键字锁升级
java对象数据由3部分组成,对象头,实例数据,对齐数据
对象头的markword大小 32bit/64bit
对象头的元数据指针大小 32bit/64bit
对象如果是数组,那么会有一个数组长度数据32bit
因为java强制要求对象大小必须为8字节的整数倍,所以会有一个对齐数据进行填充,但不是必要的
首先尝试获取偏向锁,查看对象是否开启了可偏向标志位。
其次检查锁对象对应的instanceklass对应的允许偏向位是否开启,如果没开启,表示该类的所有对象都不允许使用偏向锁。并且要把所有属于该类的对象的bias为都设置成不可使用偏向。
第三步检查锁对象的epoch位置是否有效,如果该对象的epoch位和oop-klass模型中instanceklass对象的epoch字段不匹配,那么说明这个字段可以重新偏向。此时线程可以使用cas尝试获取偏向锁。
第四步检查当前线程id和锁对象的markword的thread_id项是否相同,如果相同,说明当前线程已经获得了偏向锁。如果不相同,就进行cas尝试获取锁。
对于偏向锁有3种状态,第一种,是匿名状态,thread_id为null指还没有线程获取锁。
第二种指,可重偏向状态,锁对象的epoch字段无效。
第三种已偏向,锁对象的thread_id非空,且epoch字段有效。
偏向锁获取成功,执行同步代码块
如果经过cas获取偏向锁失败,开始撤销偏向锁,等到原持有偏向锁的线程到达安全点之后暂停线程,然后检查原持有锁的线程状态,如果已经退出同步代码块,则当前线程再次进行偏向状态检查(CAS获取锁);如果原持有锁的线程处于阻塞态,那么唤醒它,当前线程继续执行检查markword的重复操作。如果原持有锁的线程仍然处于同步代码块内,那么尝试升级成轻量级锁,就是在原持有锁的线程的栈中分配锁记录以及对象指针栈帧,把锁对象的markword拷贝到锁记录,在对象指针栈帧中存储指向对象的指针,并把锁对象的markword存储原持有锁的线程的锁记录指针,至此原持有锁对象的线程获取了轻量级锁,恢复暂停的原持有锁对象线程,等待其执行完毕并退出同步代码块,并进行轻量级解锁;如果在此期间当前线程参与了竞争轻量级锁,并且尝试cas获取轻量级线程锁,如果第一次获取失败,那么进行自旋获取,如果达到一定的次数仍然失败,那么轻量级锁膨胀为重量级锁,依赖编译后的两条字节码指令monitorenter和monitorexit分别进入和退出,当执行monitorenter指令时,线程获取锁对象对应的monitor对象的所有权。至此synchronized的锁获取以及锁升级过程解析完毕。
下面来讲锁粗化,就是把一个线程的多次加锁、解锁过程转化成一个加锁、解锁操作的过程,减少了加锁解锁的开销。
锁消除,在编译期,编译器通过逃逸分析找到不可能引起资源竞争的同步代码块,并消除加在上面的锁。
逃逸分析,逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中,称为方法逃逸。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值