在JDK1.6之后synchronized 的效率已经和JUC中的ReentenerLock效率相差无几,在深入理解java虚拟机中也有提到。那么jvm团队做了哪些优化呢?

1.基础

利用synchronized实现同步的基础:Java中的每一个对象都可以作为锁。具体表现 为以下3种形式。 ·
对于普通同步方法,锁是当前实例对象。 ·
对于静态同步方法,锁是当前类的Class对象。
对于同步方法块,锁是Synchonized括号里配置的对象。

2.自旋锁和自适应自旋锁

为了让线程等 待,我们只需让线程执行一个忙循环(自旋),这项技术就是所谓的自旋锁。 自旋锁在JDK 1.4.2中就已经引入,只不过默认是关闭的,可以使用-XX:+UseSpinning 参数来开启,在JDK 1.6中就已经改为默认开启了。自旋等待不能代替阻塞,且先不说对处 理器数量的要求,自旋等待本身虽然避免了线程切换的开销,但它是要占用处理器时间的, 因此,如果锁被占用的时间很短,自旋等待的效果就会非常好,反之,如果锁被占用的时间 很长,那么自旋的线程只会白白消耗处理器资源,而不会做任何有用的工作,反而会带来性 能上的浪费。因此,自旋等待的时间必须要有一定的限度,如果自旋超过了限定的次数仍然 没有成功获得锁,就应当使用传统的方式去挂起线程了。自旋次数的默认值是10次,用户可 以使用参数-XX:PreBlockSpin来更改。 在JDK 1.6中引入了自适应的自旋锁。自适应意味着自旋的时间不再固定了,而是由前 一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等 待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也很有 可能再次成功,进而它将允许自旋等待持续相对更长的时间,比如100个循环。另外,如果 对于某个锁,自旋很少成功获得过,那在以后要获取这个锁时将可能省略掉自旋过程,以避 免浪费处理器资源。有了自适应自旋,随着程序运行和性能监控信息的不断完善,虚拟机对 程序锁的状况预测就会越来越准确,虚拟机就会变得越来越“聪明”了。
---------- 深入理解java虚拟机
这里是引用

2.锁粗化和锁消除

锁消除是说比如在一个线程运行栈中的变量加锁,虚拟机会自动去掉这个锁,你可能会问,谁会在这个地方加锁呢,这可能是你无意识的,比如String的连接操作在底层会被改成StringBuider的连续append操作,而这些操作时加锁的。

java偏向锁流程轻量锁 java 轻量锁_加锁


锁粗化简单的说就是在连续对一个对象进行加锁的时候,虚拟机会将锁的力度扩大到这几个连续加锁的代码外,看起来就是只加一个锁。同样是StringBuilder的连续append方法。

Java SE 1.6为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”,在 Java SE 1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状 态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级,意味着偏 向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高 获得锁和释放锁的效率,下文会详细分析

1.偏向锁

HotSpot 的作者经过研究发现,大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需简单地测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。如果测试成功,表示线程已经获得了锁。如果测试失败,则需要再测试一下Mark Word中偏向锁的标识是否设置成1(表示当前是偏向锁):如果没有设置,则使用CAS竞争锁;如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程。

2.轻量级锁

轻量级锁是由偏向所升级来的,偏向锁运行在一个线程进入同步块的情况下,当第二个线程加入锁争用的时候,偏向锁就会升级为轻量级锁;

3.重量级锁

内置锁在Java中被抽象为监视器锁(monitor)。在JDK 1.6之前,监视器锁可以认为直接对应底层操作系统中的互斥量(mutex)。这种同步方式的成本非常高,包括系统调用引起的内核态与用户态切换、线程阻塞造成的线程切换等。因此,后来称这种锁为“重量级锁”。

基础2 对象头

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

而对象头根据锁状态的不同表示的也有所不同

java偏向锁流程轻量锁 java 轻量锁_自旋锁_02


当一个对象被创建后 根据虚拟机的配置,会在这个对象对象头中设置改对象是否可偏向,1表示可以偏向 0表示不可偏

java偏向锁流程轻量锁 java 轻量锁_自旋锁_03

具体见下图

java偏向锁流程轻量锁 java 轻量锁_加锁_04