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 原理章节全部内容

相关推荐
Catfood_Eason6 分钟前
CMPP3020作业2
java·开发语言
CryptoRzz8 分钟前
印度实时股票数据源接口对接文档-IPO新股、k线数据
java·开发语言·数据库·区块链
宸津-代码粉碎机14 分钟前
Java内部类内存泄露深度解析:原理、场景与根治方案(附GC引用链分析)
java·开发语言·jvm·人工智能·python
東雪木40 分钟前
Java基础语言进阶学习——1,JVM内存模型(堆、栈、方法区)
java·jvm·学习
毕设源码-郭学长1 小时前
【开题答辩全过程】以 常二社区线上养老院管理系统为例,包含答辩的问题和答案
java·eclipse
yychen_java2 小时前
基于Java3D与Jzy3D的三维建模深度开发:从架构到实践
java·3d·架构
optimistic_chen2 小时前
【Java EE进阶 --- SpringBoot】统一功能处理(拦截器)
spring boot·后端·java-ee·log4j·拦截器
lang201509282 小时前
Maven 入门指南
java·maven
xrkhy2 小时前
Java全栈面试题及答案汇总(2)
java·开发语言
Java爱好狂.3 小时前
接上篇:如何在项目中实现ES查询功能?
java·运维·jenkins·es·java面试·后端开发·java程序员