多线程synchronized 中的 锁优化的机制 (偏向锁-;轻量级锁-;重量级锁)

Posted Perceus

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程synchronized 中的 锁优化的机制 (偏向锁-;轻量级锁-;重量级锁)相关的知识,希望对你有一定的参考价值。

@TOC


synchronized 的 锁优化的机制

这也是属于我们编译器优化,以及说 JVM ,操作系统,它们的一些优化策略所涉及到一些小细节。


基本特点

结合上面的锁策略, 我们就可以总结出

Synchronized 具有以下特性(只考虑 JDK 1.8):


加锁工作过程


1. 偏向锁

举个栗子理解偏向锁 :

文里的偏向锁,和懒汉模式也有点像,思路都是一致的,只是在必要的时候,才进行操作,如果不必要,则能省就省


2. 轻量级锁

其他线程进入竞争,偏向锁状态被消除,进入轻量级锁状态 (自适应的自旋锁).

此处的轻量级锁就是通过 CAS 来实现

  • 通过 CAS 检查并更新一块内存 (比如 null => 该线程引用)
  • 如果更新成功, 则认为加锁成功
  • 如果更新失败, 则认为锁被占用, 继续自旋式的等待(并不放弃 CPU)

3. 重量级锁

如果竞争进一步激烈, 自旋不能快速获取到锁状态, 就会膨胀为重量级锁

此处的重量级锁就是指用到内核提供的 mutex

  • 执行加锁操作, 先进入内核态.
  • 在内核态判定当前锁是否已经被占用
  • 如果该锁没有占用, 则加锁成功, 并切换回用户态.
  • 如果该锁被占用, 则加锁失败. 此时线程进入锁的等待队列, 挂起. 等待被操作系统唤醒.
  • 经历了一系列的沧海桑田, 这个锁被其他线程释放了, 操作系统也想起了这个挂起的线程, 于是唤醒这个线程, 尝试重新获取锁

synchronized 几个典型的优化手段

1、锁膨胀/锁升级


2、锁粗化


举个栗子理解锁粗化 :


到底锁粒度是粗好还是细好?


3、锁消除

就比如你当前的代码是处于单线程的情况,你还咔咔的顿加锁操作。
这个时候,编译器就会你创建的锁,都去掉。

疑问:单线程的代码,有谁会去加锁的?

其实有时候加锁操作并不是很明显,稍不留神就可能会做出这种错误的决定。

StringBuffer sb = new StringBuffer();
sb.append("a");
sb.append("b");
sb.append("c");
sb.append("d");

此时每个 append 的调用都会涉及加锁和解锁,但如果只是在单线程中执行这个代码,那么这些加锁解

锁操作是没有必要的,白白浪费了一些资源开销


以上是关于多线程synchronized 中的 锁优化的机制 (偏向锁-;轻量级锁-;重量级锁)的主要内容,如果未能解决你的问题,请参考以下文章

java 多线程9 : synchronized锁机制 之 代码块锁

002-多线程-锁-同步锁-synchronized几种加锁方式Java对象头和MonitorMutex LockJDK1.6对synchronized锁的优化实现

java多线程——锁机制synchronized(同步方法)

synchronized实现原理及其优化-(自旋锁,偏向锁,轻量锁,重量锁)

Java多线程之synchronized及其优化

java 多线程8 : synchronized锁机制 之 方法锁