多线程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(同步方法)