sychronized 锁升级

Posted 盖丽男

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sychronized 锁升级相关的知识,希望对你有一定的参考价值。

sychronize有几种锁

sychronize
1.6之前,只存在重量级锁,也就是一个线程拿到锁之后,其他没有拿到锁的线程只能阻塞。
1.6之后,新加了偏向锁和轻量级锁(自旋锁)。

无锁

无锁是指没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功。

也就是说,理想情况下,所有获取锁的线程都能够在第一次尝试的时候就成功,也就是没有真正发生竞争,此时,sychronized不会真正的加锁。
实际上不是这样。当对象刚被new出来的时候,没有线程进行访问,此时是无锁状态,一旦有线程来访问,其实第一个线程会加偏向锁。或者偏向锁撤销 对象头中的mark word 是空的时候 也是无锁状态。

也就是不存在多个线程访问,互相不冲突,大家维持友好的无锁状态这种事。

偏向锁

偏向锁是指当一段同步代码一直被同一个线程所访问时,即不存在多个线程的竞争时,那么该线程在后续访问时便会自动获得锁,从而降低获取锁带来的消耗,即提高性能。

也就是说,此时也没有发生真正的竞争,可以理解为不存在第二个线程来获取锁,当对象被第一个线程访问,当锁对象第一次被线程获取的时候,虚拟机会把对象头中的标志位设为01、把偏向模式设置为1,表示进入偏向模式。同时使用CAS操作把获取到这个锁的线程的ID记录在对象的Mark Word中,如果CAS操作成功,持有偏向锁的线程以后每次进入这个锁相关的同步块时。虚拟机都可以不再进行任何同步操作(例如加锁、解锁以及对Mark Word的更新操作等)。

轻量级锁/自旋锁

轻量级锁是指当锁是偏向锁的时候,却被另外的线程所访问,此时偏向锁就会升级为轻量级锁,其他线程会通过自旋(关于自旋的介绍见文末)的形式尝试获取锁,线程不会阻塞,从而提高性能。

轻量级锁的获取主要由两种情况:① 当关闭偏向锁功能时;② 由于多个线程竞争偏向锁导致偏向锁升级为轻量级锁。

也就是说,一旦发生了两个线程同时获取一把锁的情况,偏向锁就不合适了,会升级成轻量级锁,之所以称之为“轻量”,是因为其他没有获取到锁的线程并不会进入阻塞状态,而是会进入“自旋”,其实就是进入循环,循环内会尝试继续获取锁。

可以看一下偏向锁到轻量级锁的升级过程

  1. 在代码即将进入同步块的时候,如果此同步对象没有被锁定(锁标志位为01状态),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录的空间,用于存储锁对象目前的Mark Word拷贝(官方为这份拷贝加了个前缀Displaced)。
  2. 然后虚拟机将使用CAS操作尝试把对象的Mark Word更新为指向Lock Record的指针。如果这个更新动作成功了,即代表该线程拥有了这个对象的锁,并且对象Mark Word的锁标志位(Mark Word的最后两个比特)将转变为00,表示此对象处于轻量级锁定状态。
  3. 如果这个操作失败了,那就意味着至少存在一条线程与当前线程竞争获取该对象的锁。虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧。如果是,说明当前线程已经拥有了这个对象的锁,那直接进入同步块继续执行就可以了,否则就说明这个锁对象已经被其他线程抢占了。当前线程会进行自旋。
  4. 如果出现两条以上的线程争用同一个锁,或者当前线程自旋失败(尝试到一定次数,默认10次)的情况,那轻量级锁就不再有效,必须要膨胀为重量级锁,锁标志的状态值变为10,此时Mark Word中存储的就是指向重量级锁监视器ObjectMonitor(互斥量)的指针,后面等待锁的线程也必须进入阻塞状态。

重量级锁

重量级锁是指当有一个线程获取锁之后,其余所有等待获取该锁的线程都会处于阻塞状态。

重量级锁通过对象内部的监视器(monitor)实现,而其中 monitor 的本质是依赖于底层操作系统的 Mutex Lock 实现,操作系统实现线程之间的切换需要从用户态切换到内核态,切换成本非常高。

简而言之,重量级锁和我们平常使用的lock区别不大,一旦有一个线程获取到了锁,其他没有获取到锁的线程都只能进入阻塞状态排队。

锁升级状态

所以,锁升级有两条线路:

  1. 偏向锁打开的情况下,当对象被new出来,此时是无锁,当第一个线程来访问并获取锁的时候,加一个偏向锁,如果在第一个线程持有偏向锁期间,有其他的线程也来获取锁,那么此时升级为轻量级锁,如果竞争比较激烈,比如自旋的线程尝试多次仍旧获取不到锁,就有可能升级为重量级锁。也就是无锁→偏向锁→轻量级锁→重量级锁
  2. 偏向锁关闭的情况下,当对象被new出来,此时是无锁,当第一个线程来访问,直接就加轻量级锁,如果竞争比较激烈,比如自旋的线程尝试多次仍旧获取不到锁,就有可能升级为重量级锁。也就是无锁→轻量级锁→重量级锁

总结

以上是我的思考,有不对的地方欢迎大家指出(我觉得肯定有不对的地方,可是现阶段我就是这么理解的,希望大家积极指出),感谢大家帮助我提高。

参考

synchronized与锁升级(示例代码)
synchronized四种锁状态的升级

以上是关于sychronized 锁升级的主要内容,如果未能解决你的问题,请参考以下文章

sychronized

JAVA面试题 请谈谈你对Sychronized关键字的理解?

MySQL锁(锁升级)

锁升级

MySQL innoDB 中的锁升级

什么是锁升级