Syncrhonized的作用方式
- 同步方法:锁是当前实例对象
- 静态同步方法:锁是类对象
- 同步代码块:锁是括号中的对象
实现同步的底层原理
JVM基于进入和退出Monitor对象来实现同步方法和同步代码块。同步方法经过编译后,会在常量池生成ACC_SYNCHRONIZED的标识符,通过给同步方法添加ACC_SYNCHRONIZED的标识符,实现同步。对于同步代码块,在编译后会在同步块前后添加monitorenter和monitorexit两条指令,实现同步。
锁的升级的过程
JDK1.6前synchronized的锁很重,但是1.6后,对synchronized关键字进行了优化,让他没有那么重了。分为4个锁级别,无锁、偏向锁、轻量级锁和重量级锁。
为偏向锁时,线程访问同步代码块时会比较线程和锁对象的对象头中的Mark word里面的线程id,如果相同可以无锁直接进入同步代码块,否则就使用CAS来竞争锁,如果成功,就改变Mark word中偏向的线程id就行了,如果失败代表出现线程的竞争,锁就会升级为轻量锁。
当为轻量锁的时候,会在线程的栈中生成一份存储锁记录的空间,并将mark word复制到锁记录中,轻量级锁如果获取锁记录失败,会进行自旋,如果在自旋期间获得了锁就进入同步代码块,否则会升级为重量级锁。
为重量级锁的时候,线程如果获取不到锁就会阻塞。避免了自旋消耗CPU资源,提升了吞吐量。
总结:偏向锁适用于没有竞争的情况,轻量级锁适合同步代码块执行时间短的情况,重量级锁适合同步代码块执行时间长的情况。