Synchronized原理

news2024/11/17 11:31:16

Synchronized原理

  • 一、基本特点
  • 二、加锁工作过程 (锁升级/锁膨胀)
    • 2.1 偏向锁
    • 2.2 轻量级锁
    • 2.3 重量级锁
  • 三、锁消除
  • 四、锁粗化
  • 五、总结

一、基本特点

结合锁策略,我们就可以总结出 Synchronized 具有以下特性(只考虑 JDK 1.8):

  1. 开始时是乐观锁, 如果锁冲突频繁, 就转换为悲观锁
  2. 开始是轻量级锁实现, 如果锁被持有的时间较长, 就转换成重量级锁
  3. 实现轻量级锁的时候大概率用到的自旋锁策略
  4. 是一种不公平锁
  5. 是一种可重入锁
  6. 不是读写锁

二、加锁工作过程 (锁升级/锁膨胀)

JVM将 synchronized 锁分为无锁、偏向锁、轻量级锁、重量级锁状态。会根据情况,进行依次升级!
在这里插入图片描述

2.1 偏向锁

第一个尝试加锁的线程,优先进入偏向锁状态。
在这里插入图片描述
偏向锁本质上相当于"延迟加锁",能不加锁就不加锁,尽量来避免不必要的加锁开销~

举个例子:假设男主是一个锁,女主是一个线程。如果只有这一个线程来使用这个锁,那么男主女主即使不领证结婚 (避免了高成本操作),也可以一直幸福的生活下去。
但是女配出现了,也尝试竞争男主,此时不管领证结婚这个操作成本多高,女主也势必要把这个动作完成了,让女配死心~~

2.2 轻量级锁

随着其他线程进入竞争,偏向锁状态被消除,进入轻量级锁状态 (自适应的自旋锁)。
此处的轻量级锁就是通过 CAS 来实现的:

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

自旋操作是一直让 CPU 空转,比较浪费 CPU 资源!
因此此处的自旋不会一直持续进行,而是达到一定的时间/重试次数,就不再自旋了。
也就是所谓的 “自适应”!

2.3 重量级锁

如果竞争进一步激烈,自旋不能快速获取到锁状态,就会膨胀为重量级锁!
此处的重量级锁就是指用到内核提供的 mutex

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

三、锁消除

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

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

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

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

四、锁粗化

锁的粒度有粗细之分,取决于synchronized对应代码块中包含多少代码。包含的代码少,粒度细;包含的代码多,粒度粗。

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

在这里插入图片描述
实际开发过程中,使用细粒度锁,是期望释放锁的时候其他线程能使用锁。
但是实际上可能并没有其他线程来抢占这个锁。这种情况JVM就会自动把锁粗化,避免频繁申请释放锁带来一些额外的锁竞争。

举个例子:
滑稽老哥当了领导,给下属交代工作任务:
方式一:
打电话,交代任务1,挂电话;
打电话,交代任务2,挂电话;
打电话,交代任务3,挂电话。
方式二:
打电话,交代任务1、任务2、任务3、挂电话。
显然,方式二是更高效的方案~~

注意:
1)得是对同一个对象加锁的才能粗化到一起!
2)锁的粒度也不是越粗就越好!像上述反复加锁的场景变粗了确实还行,但是有的时候锁太粗不利于多线程并发,有悖于写多线程的初衷了~~

五、总结

1)可以看到,synchronized 的策略是比较复杂的,在背后做了很多事情,目的为了让程序猿哪怕啥都不懂,也不至于写出特别慢的程序!(JVM 开发者为了 Java 程序猿操碎了心~~)

2)做出的优化都是在不改变逻辑的前提下进行的!

相关面试题
1)什么是偏向锁?

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

2)synchronized 实现原理是什么?

参考本篇所有内容~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/82883.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构.数组

数据结构.数组1.数组的概念和特点2.数组的定义和初始化3.数组的遍历4.数组的基本操作(不多说 注解很详细)5.操作的时间复杂度1.数组的概念和特点 数组就是一种容器(装数据的),用来存储相同类型的数据值。 数组的特点…

RRT_star MATLAB

colormap 函数 创建栅格地图 clc clear close all%% 构建颜色MAP图 cmap [1 1 1; ... % 1-白色-空地0 0 0; ... % 2-黑色-静态障碍1 0 0; ... % 3-红色-动态障碍1 1 0;... % 4-黄色-起始点 1 0 1;... % 5-品红-目标点0 1 0…

Canal同步mysql binlog至pulsar

Canal 一、简介 canal [kə’nl],主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费 基于日志增量订阅和消费的业务包括 数据库镜像数据库实时备份索引构建和实时维护(拆分异构索引、倒排索引等)业务 cache 刷新带业务逻辑的增量数据处…

【数据结构】队列(链式队列)

作者:一个喜欢猫咪的的程序员 专栏:《数据结构》 喜欢的话:世间因为少年的挺身而出,而更加瑰丽。 ——《人民日报》 目录 队列的结构和概念: Queue.h文件 Queue.c文件 Test.c文件&am…

ElasticSearch分布式架构原理

一个ES集群中有多个Server节点,每个Server节点中含有多个Index。 主节点(Master) 主资格节点的主要职责是和集群操作相关的内容,如创建或删除索引,跟踪哪些节点是集群的一部分,并决定哪些分片分配给相关的…

文件系统篇

目录 1.文件系统的基本组成 1.1.文件 1.1.1.目录项和目录是一个东西吗? 1.1.2.那文件数据是如何存储在磁盘的呢? 2.page cache 2.1.进程写文件时,进程发生了崩溃,已写入的数据会丢失吗 2.2.page cache是什么? …

Docker:网络配置

目录 一、网络模式简介 二、bridge模式以及host模式的命令演示 bridge模式 host模式 三、自定义网络 一、网络模式简介 Docker在创建容器时有四种网络模式:bridge/host/container/none,bridge为默认不需要用--net去指定,其他三种模式需要…

CAS机制和synchronize的原理及其优化机制(锁消除 偏向锁 自旋锁 膨胀锁 锁粗化)

乐观锁的问题:并不总是能处理所有问题,所以会引入一定的系统复杂度。 读写锁 把加锁操作分成了俩种 一是读锁二是写锁 也就是说在读和读之间是没有互斥的 但是在读写和写写之间就会存在互斥 如果一个场景是一写多度 那么使用这个效率就会很高 重量级锁…

【数据结构与算法】B_树

目录 前言: 一、B树 1、B树概念 2、B树查找 3、B树插入 4、B树前序遍历 5、B树性能 二、B、B*树 1、B树概念 2、B树的插入 2、B*树概念 3、总结 三、B系列树的应用 总结 前言: 我们已经有很多索引的数据结构了 例如: 顺序查找 …

CAD外部参照文件的分解

最近遇到一个编图要求: “图纸文件的内容主要由模型空间和布局空间内的信息组成,尽量减少外部参照的使用。” 我们的综合图分幅主要依照外部参照来的,图件的本体只有1个,分幅图中只有布局试图有点线面等实体存在,模型…

阿里二面:用过GC日志可视化工具进行JVM调优吗?

上周有个小伙伴面了阿里,在二面中被问到GC日志分析,感觉回答的不是很好,过来找我复盘,大致听了他的回答,虽然回答出了部分,但是没抓到重点。 GC日志分析算是JVM调优中比较难的部分,今天这篇文章…

0123 双指针 Day12

剑指 Offer 25. 合并两个排序的链表 输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。 示例1: 输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4 /*** Definition for si…

安科瑞嵌入式多功能计量表AEM96 精度0.5S级 2-31次分次谐波

安科瑞 王晶淼/刘芳 一、产品概述 AEM系列三相嵌入式电能计量表是一款主要针对电力系统、工矿企业、公用设施的电能统计、管理需求而设计的智能电能表,集成三相电力参数测量及电能计量与考核管理,提供上24时,上31日以及上12月的电能数据统计…

DNS 区域传送漏洞(dns-zone-tranfer)学习

DNS 区域传送漏洞(dns-zone-tranfer)学习 ———— 相关知识理解 DNS(域名系统)就像一个互联网电话簿。它负责将人类可读的主机名解析为机器可读的 IP 地址。 DNS服务器分为主服务器,备份服务器,缓存服务…

【Docker】多个容器和宿主机之间如何进行数据同步和数据共享?容器数据卷从介绍到常用操作图文教程

专栏往期文章 《Docker是什么?Docker从介绍到Linux安装图文详细教程》《30条Docker常用命令图文举例总结》《Docker如何构建自己的镜像?从镜像构建到推送远程镜像仓库图文教程》 前言 你是否担心 Docker 容器被删除后,容器内的重要数据就丢…

VFIDILDKVENAIHNAAQVGIGFAKPFEKLINPK,果蝇抗菌肽

果蝇抗菌肽是一种含有Lys的抗菌多肽,序列中包含34个氨基酸,是一种含有α-折叠的抗菌多肽。 编号: 223981中文名称: 果蝇抗菌肽,Andropin英文名: Antimicrobial Peptide Andropin单字母: H2N-VFIDILDKVENAIHNAAQVGIGFAKPFEKLINPK-OH三字母: H2…

自然语言处理(NLP)数据集汇总 3(附下载链接)

🎄🎄【自然语言处理NLP】简介 🎄🎄 自然语言处理(Natural Language Processing, NLP)是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自然语言处理是一门…

Allure:根据step动态设置description

背景 使用pytestAllure进行自动化的时候,为了报告展示更明确会使用 with allure.step(xxx)和 allure.step(xxx)测试结束后就可以看到 测试步骤 Allure还支持配置Description 之前直接在case中编写,例如 """ [用例描述]: 专家问诊 [前置步骤]:1. 打开h5页面…

ScheduledExecutorService的使用及守护线程

只运行一次 private static ScheduledExecutorService scheduler; public static void main(String[] args) throws Exception { scheduler Executors.newScheduledThreadPool(5); // 循环任务,按照上一次任务的发起时间计算下一次任务的开始时间 scheduler.schedu…

解决mysql存储emoji表情唯一索引报错问题

问题发现: 1、正常上班的一天,突然间有运营同事反馈,我们在添加数据的时候,发现添加了🐸之后,对应的💩没有了,添加了💩然后🐸就没有了,需要研发帮…