Java EE初阶启程记12---synchronized 原理

🔥个人主页: 寻星探路

🎬作者简介:Java研发方向学习者

📖个人专栏:、《

⭐️人生格言:没有人生来就会编程,但我生来倔强!!!



目录

一、基本特点

二、加锁工作过程

1、偏向锁

2、轻量级锁

3、重量级锁

三、其他的优化操作

1、锁消除

2、锁粗化

四、相关面试题

1、什么是偏向锁?

[2、synchronized 实现原理是什么?](#2、synchronized 实现原理是什么?)


一、基本特点

结合上面的锁策略,我们就可以总结出,synchronized具有以下特性(只考虑JDK1.8):

1)开始时是乐观锁,如果锁冲突频繁,就转换为悲观锁。

2)开始是轻量级锁实现,如果锁被持有的时间较长,就转换成重量级锁。

3)实现轻量级锁的时候大概率用到的自旋锁策略。

4)是一种不公平锁。

5)是一种可重入锁。

6)不是读写锁。

二、加锁工作过程

JVM 将 synchronized 锁分为无锁、偏向锁、轻量级锁、重量级锁状态。会根据情况,进行依次升级。

1、偏向锁

第一个尝试加锁的线程,优先进入偏向锁状态。

偏向锁不是真的"加锁",只是给对象头中做一个"偏向锁的标记",记录这个锁属于哪个线程。

如果后续没有其他线程来竞争该锁,那么就不用进行其他同步操作了(避免了加锁解锁的开销)

如果后续有其他线程来竞争该锁(刚才已经在锁对象中记录了当前锁属于哪个线程了,很容易识别当前申请锁的线程是不是之前记录的线程),那就取消原来的偏向锁状态,进入一般的轻量级锁状态。

偏向锁本质上相当于"延迟加锁",能不加锁就不加锁,尽量来避免不必要的加锁开销。

但是该做的标记还是得做的,否则无法区分何时需要真正加锁。

举个例子理解偏向锁:

假设男主是一个锁,女主是一个线程,如果只有这一个线程来使用这个锁,那么男主女主即使不领证结婚(避免了高成本操作),也可以一直幸福的生活下去。

但是女配出现了,也尝试竞争男主,此时不管领证结婚这个操作成本多高,女主也势必要把这个动作完成了,让女配死心。

2、轻量级锁

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

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

通过CAS检查并更新一块内存(比如null=>该线程引用)。

如果更新成功,则认为加锁成功。

如果更新失败,则认为锁被占用,继续自旋式的等待(并不放弃CPU)。

自旋操作是一直让CPU空转,比较浪费CPU资源。

因此此处的自旋不会一直持续进行,而是达到一定的时间/重试次数,就不再自旋了。

也就是所谓的"自适应"。

3、重量级锁

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

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

执行加锁操作,先进入内核态。

在内核态判定当前锁是否已经被占用。

如果该锁没有占用,则加锁成功,并切换回用户态。

如果该锁被占用,则加锁失败。此时线程进入锁的等待队列,挂起,等待被操作系统唤醒。

经历了一系列的沧海桑田,这个锁被其他线程释放了,操作系统也想起了这个挂起的线程,于是唤醒这个线程,尝试重新获取锁。

三、其他的优化操作

1、锁消除

编译器+JVM判断锁是否可消除,如果可以,就直接消除。

什么是"锁消除"?

有些应用程序的代码中,用到了synchronized,但其实没有在多线程环境下。(例如StringBuffer)

java 复制代码
 StringBuffer sb = new StringBuffer();
 sb.append("a");
 sb.append("b");
 sb.append("c");
 sb.append("d");

此时每个append的调用都会涉及加锁和解锁,但如果只是在单线程中执行这个代码,那么这些加锁解锁操作是没有必要的,白白浪费了一些资源开销。

2、锁粗化

一段逻辑中如果出现多次加锁解锁,编译器+JVM会自动进行锁的粗化。

锁的粒度:粗和细

实际开发过程中,使用细粒度锁,是期望释放锁的时候其他线程能使用锁。

但是实际上可能并没有其他线程来抢占这个锁,这种情况JVM就会自动把锁粗化,避免频繁申请释放锁。

举个例子理解锁粗化:

滑稽老哥当了领导,给下属交代工作任务:

方式一:

打电话,交代任务1,挂电话。

打电话,交代任务2,挂电话。

打电话,交代任务3,挂电话。

方式二:

打电话,交代任务1,任务2,任务3,挂电话。

显然,方式⼆是更高效的方案。

可以看到,synchronized的策略是比价复杂的,在背后做了很多事情,目的为了让程序猿哪怕啥都不懂,也不至于写出特别慢的程序。

JVM开发者为了Java程序猿操碎了心。

四、相关面试题

1、什么是偏向锁?

偏向锁不是真的加锁,而只是在锁的对象头中记录一个标记(记录该锁所属的线程)。如果没有其他线程参与竞争锁,那么就不会真正执行加锁操作,从而降低程序开销,一旦真的涉及到其他的线程竞争,再取消偏向锁状态,进入轻量级锁状态。

2、synchronized 实现原理是什么?

参考上面的 synchronized 原理章节全部内容

相关推荐
qq_574656252 小时前
java代码随想录day50|图论理论基础
java·算法·leetcode·图论
蒋星熠2 小时前
Maven项目管理与构建自动化完全指南
java·前端·python·自动化·maven
sheji34162 小时前
【开题答辩全过程】以 ssm框架的智能校园服务系统为例,包含答辩的问题和答案
java·eclipse
青云交3 小时前
Java 大视界 -- 基于 Java 的大数据实时流处理在工业物联网设备故障预测与智能运维中的应用
java·flink·kafka·工业物联网·设备故障预测·智能运维·实时流处理
fat house cat_3 小时前
为什么RocketMQ选择mmap+write?RocketMQ零拷贝技术深度解析
java·rocketmq·零拷贝
月疯3 小时前
FLASK与JAVA的文件互传并带参数以及流上传(单文件互传亲测)
java·python·flask
Stream_Silver3 小时前
LangChain入门实践3:PromptTemplate提示词模板详解
java·python·学习·langchain·language model
小树懒(-_-)4 小时前
SEO:Java项
java·开发语言
TeleostNaCl4 小时前
如何在 IDEA 中使用 Proguard 自动混淆 Gradle 编译的Java 项目
android·java·经验分享·kotlin·gradle·intellij-idea