Synchronized关键字的深入分析

news2024/11/24 14:19:56

一、引言

在多线程编程中,正确地管理并发是确保程序正确运行的关键。Java提供了多种同步工具,其中synchronized关键字是最基本且最常用的同步机制之一。本文旨在深入解析synchronized的实现原理,探讨其在不同应用场景中的使用,并通过示例让读者更好地理解其工作机制。

二、Synchronized基本概念

2.1 定义和作用

synchronized关键字可以用来修饰方法或者代码块。在方法或代码块被执行时,它能够保证同一时刻只有一个线程执行该段代码。这一特性使得synchronized成为实现临界区(Critical Section)和避免竞态条件(Race Condition)的简便方法。

2.2 使用方法

  • 同步实例方法:锁定当前实例对象
public synchronized void method() {
    // 同步代码
}

  • 同步静态方法:锁定当前类的Class对象。
public static synchronized void staticMethod() {
    // 同步代码
}

  • 同步代码块:指定一个特定对象作为锁。
public void method() {
    synchronized(this) {
        // 同步代码
    }
}

2.3 对比其他关键字

volatilefinal相比,synchronized不仅能保证可见性和顺序性,还能保证原子性。volatile仅保证变量的修改可见性和禁止指令重排序,而final关键字则用于声明常量。

三、Synchronized的内部机制

3.1 Java内存模型(JMM)

JMM处理了变量的可见性、原子性问题,为开发者屏蔽了不同CPU的复杂性。它确保一个线程对共享变量的修改,能够被其他线程看到,是通过内存屏障实现的。

3.2 锁的状态

在 JDK 6 中虚拟机团队对锁进行了重要改进,优化了其性能引入了 偏向锁、轻量级锁、适应性自旋、锁消除、锁粗化等实现,其中 锁消除和锁粗化本文不做详细讨论其余内容我们将对其进行逐一探究。

总体上来说锁状态升级流程如下:
在这里插入图片描述

  • 无锁状态
  • 偏向锁:假定锁不会存在竞争,避免了大多数情况下的同步。
  • 轻量级锁:当锁是偏向锁时,被另一个线程访问,会升级为轻量级锁。
  • 重量级锁:多线程竞争激烈时,轻量级锁会升级为重量级锁。

3.3 各种锁的获取流程

偏向锁
流程

当线程访问同步块并获取锁时处理流程如下:

  • 检查 mark word 的线程 id 。
  • 如果为空则设置 CAS 替换当前线程 id。如果替换成功则获取锁成功,如果失败则撤销偏向锁。
  • 如果不为空则检查 线程 id为是否为本线程。如果是则获取锁成功,如果失败则撤销偏向锁。

持有偏向锁的线程以后每次进入这个锁相关的同步块时,只需比对一下 mark word 的线程 id 是否为本线程,如果是则获取锁成功。

如果发生线程竞争发生 2、3 步失败的情况则需要撤销偏向锁。

偏向锁的撤销
  1. 偏向锁的撤销动作必须等待全局安全点
  2. 暂停拥有偏向锁的线程,判断锁对象是否处于被锁定状态
  3. 撤销偏向锁恢复到无锁(标志位为 01)或轻量级锁(标志位为 00)的状态
优点

只有一个线程执行同步块时进一步提高性能,适用于一个线程反复获得同一锁的情况。偏向锁可以提高带有同步但无竞争的程序性能。

缺点

如果存在竞争会带来额外的锁撤销操作。

轻量级锁
加锁

多个线程竞争偏向锁导致偏向锁升级为轻量级锁

  1. JVM 在当前线程的栈帧中创建 Lock Reocrd,并将对象头中的 Mark Word 复制到 Lock Reocrd 中。(Displaced Mark Word)
  2. 线程尝试使用 CAS 将对象头中的 Mark Word 替换为指向 Lock Reocrd 的指针。如果成功则获得锁,如果失败则先检查对象的 Mark Word 是否指向当前线程的栈帧如果是则说明已经获取锁,否则说明其它线程竞争锁则膨胀为重量级锁。
解锁
  1. 使用 CAS 操作将 Mark Word 还原
  2. 如果第 1 步执行成功则释放完成
  3. 如果第 1 步执行失败则膨胀为重量级锁。
优点

其性能提升的依据是对于绝大部分的锁在整个生命周期内都是不会存在竞争。在多线程交替执行同步块的情况下,可以避免重量级锁引起的性能消耗。

缺点

在有多线程竞争的情况下轻量级锁增加了额外开销。

自旋锁

自旋是一种获取锁的机制并不是一个锁状态。在膨胀为重量级锁的过程中或重入时会多次尝试自旋获取锁以避免线程唤醒的开销,但是它会占用 CPU 的时间因此如果同步代码块执行时间很短自旋等待的效果就很好,反之则浪费了 CPU 资源。默认情况下自旋次数是 10 次用户可以使用参数 -XX : PreBlockSpin 来更改。那么如何优化来避免此情况发生呢?我们来看适应性自旋。

适应性自旋锁

JDK 6 引入了自适应自旋锁,意味着自旋的次数不在固定,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果对于某个锁很少自旋成功那么以后有可能省略掉自旋过程以避免资源浪费。有了自适应自旋随着程序运行和性能监控信息的不断完善,虚拟机对程序锁的状况预测就会越来越准确,虛拟机就会变得越来越“聪明”了。

优点

竞争的线程不会阻塞挂起,提高了程序响应速度。避免重量级锁引起的性能消耗。

缺点

如果线程始终无法获取锁,自旋消耗 CPU 最终会膨胀为重量级锁。

重量级锁

在重量级锁中没有竞争到锁的对象会 park 被挂起,退出同步块时 unpark 唤醒后续线程。唤醒操作涉及到操作系统调度会有额外的开销。

ObjectMonitor 中包含一个同步队列(由 _cxq_EntryList 组成)一个等待队列( _WaitSet )。

  • 被notify或 notifyAll 唤醒时根据 policy 策略选择加入的队列(policy 默认为 0)
  • 退出同步块时根据 QMode 策略来唤醒下一个线程(QMode 默认为 0)

这里稍微提及一下管程这个概念。synchronized 关键字及 waitnotifynotifyAll 这三个方法都是管程的组成部分。可以说管程就是一把解决并发问题的万能钥匙。有两大核心问题管程都是能够解决的:

  • 互斥:即同一时刻只允许一个线程访问共享资源;
  • 同步:即线程之间如何通信、协作。

synchronizedmonitor锁机制和 JDK 并发包中的 AQS 是很相似的,只不过 AQS 中是一个同步队列多个等待队列。熟悉 AQS 的同学可以拿来做个对比。

3.3 锁升级过程

锁的升级是自动的,以减少锁的开销。例如,从偏向锁到轻量级锁的升级发生在第一个获取偏向锁的线程之外的线程尝试获取这个锁时。

3.4 对象头和锁标记位

Java对象头包含了对象的运行时数据,例如哈希码、GC标记位、锁状态等。这些信息对于锁的管理至关重要。
在这里插入图片描述

附录:队列协作流程图

在这里插入图片描述

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

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

相关文章

vue3第二十五节(h()函数的应用)

1、前言: 为什么vue 中已经有 template 模板语法,以及JSX了,还要使用 h()渲染函数; vue 中选择默认使用template 静态模板分析,有利于DMO性能的提升,而且更接近真实的HTML,便于开发设计人员理…

工业测径仪的应用场景和可靠性判断

关键字:线缆测径仪,圆棒测径仪,圆管测径仪,金属棒管测径仪,工业测径仪,智能测径仪 智能测径仪主要应用于以下领域: 金属加工:测量金属线材、棒材、管材等的直径。线缆制造:检测电线、电缆的直径。塑料管材生产:监控塑料管材的外…

BGP的路径属性

路径属性 l每条BGP路由都拥有多个的路径属性,有些是必须携带的,有些是可选添加的 lBGP的路径属性将影响最优路由的选择 lBGP路径属性是描述路由的一组参数,BGP根据路由的属性选择最佳路由,可以人为置值,以便执行路由…

第十五届蓝桥杯省赛第二场C/C++B组E题【遗迹】题解

解题思路 错解 贪心:每次都移动至当前最近的对应方块上。 反例: s s s abxac t t t abac 贪心结果(下标) 0 → 1 → 0 → 4 0 \rightarrow 1 \rightarrow 0 \rightarrow 4 0→1→0→4,答案为 5 5 5。 正确结…

六天以太坊去中心化租房平台,前端+合约源码

六天以太坊去中心化租房平台 概述项目结构合约部署运行项目功能介绍一、首页二、房东后台我的房屋我的订单上架新房屋 三、租户后台我的房屋我的订单 四、仲裁后台 下载地址 概述 六天区块链房屋租赁系统,采用去中心化的方式实现了房屋的租赁功能。房东可在平台上托…

第二节:反相器、与非门Verilog实现

1.反相器 module inv(A,Y);//A,Y是我的端口 input A;//定义属性 output Y; assign Y ~A;//定义输入输出关系 endmodule //testbench of inv timescale 1ns/10ps//1ns是时间单位,10ps为精度 module inv_tb; reg a; wire y; inv inv(.A(a),.Y(y)); initial begin a…

图片批量高效管理,轻松调整图片着色,让图片瞬间焕发新生!

在数字化时代,图片成为了我们生活与工作中不可或缺的一部分。然而,面对海量的图片资源,如何高效、便捷地管理并调整它们的着色,成为了许多人的挑战。现在,我们为您带来了一款全新的图片批量管理工具,让您轻…

【计算机系统基础读书笔记】1.1.2 冯诺依曼机基本结构

1.1.2 冯诺依曼机基本结构 冯诺依曼机基本结构如图所示: 模型机中主要包括: 主存储器:用来存放指令和数据,简称主存或内存; 算数逻辑部件(Arithmetic Logic Unit,简称ALU)&#x…

【数据结构】链表的中间节点

给你单链表的头结点 head ,请你找出并返回链表的中间结点。 如果有两个中间结点,则返回第二个中间结点。 Definition for singly-linked list.struct ListNode {int val;struct ListNode *next;};typedef struct ListNode ListNode; struct ListNode…

Apache RocketMQ ACL 2.0 全新升级

作者:徒钟 引言 RocketMQ 作为一款流行的分布式消息中间件,被广泛应用于各种大型分布式系统和微服务中,承担着异步通信、系统解耦、削峰填谷和消息通知等重要的角色。随着技术的演进和业务规模的扩大,安全相关的挑战日益突出&am…

python批量删除文件

python批量删除文件 1、查询与删除2、添加模块到地址中3、批量删除多个路径中不需要导出的文件 1、查询与删除 mport osdef get_files_in_folder(folder_path):files []for file in os.listdir(folder_path):if os.path.isfile(os.path.join(folder_path, file)):files.appen…

【Leetcode】vector刷题

🔥个人主页:Quitecoder 🔥专栏:Leetcode刷题 目录 1.只出现一次的数字2.杨辉三角3.删除有序数组中的重复项4.只出现一次的数字II5.只出现一次的数字III6.电话号码的字母组合 1.只出现一次的数字 题目链接:136.只出现一…

微信小程序自定义导航栏定位及胶囊按钮图解

在自定义小程序导航栏时,右上角的胶囊(MenuButton)在不同机型测试,会发现很难适配。 实测中 不同的手机,胶囊高度不一样、状态栏高度不一样。与模拟器显示的情况是不一样的。 由于小程序在不同的手机上顶部布局会发生…

C语言 | Leetcode C语言题解之第44题通配符匹配

题目&#xff1a; 题解&#xff1a; bool allStars(char* str, int left, int right) {for (int i left; i < right; i) {if (str[i] ! *) {return false;}}return true; } bool charMatch(char u, char v) { return u v || v ?; };bool isMatch(char* s, char* p) {in…

以太网口硬件知识分享

一、了解网口通信基本原理 实现网络通信实质上是PHY与MAC及RJ45接口实现信号传输。MAC 就是以太网控制器&#xff0c;MAC属于数据链路层&#xff0c;主要负责把数据封装成帧&#xff0c;对帧进行界定实现帧同步。对MAC地址和源MAC地址及逆行相应的处理并对错误帧进行处理。PHY…

To String的几个作用

To String的几个作用 一、Object类中toString的作用 1、在主方法中我们可以直接用toString输出对象其中的内容 2、我们需要直接输出对象中所属内容时&#xff0c;直接使用toString方法输出语句&#xff0c;输出内容不友好&#xff0c;不便于阅读 子类&#xff1a; public c…

机器学习-保险花销预测笔记+代码

读取数据 import numpy as np import pandas as pddatapd.read_csv(rD:\人工智能\python视频\机器学习\5--机器学习-线性回归\5--Lasso回归_Ridge回归_多项式回归\insurance.csv,sep,) data.head(n6) EDA 数据探索 import matplotlib.pyplot as plt %matplotlib inlineplt.hi…

Python实现飞机大战

提供学习或者毕业设计使用&#xff0c;功能基本都有&#xff0c;不能和市场上正式游戏相提比论&#xff0c;请理性对待&#xff01; 本博文将开启免费试读&#xff0c;如有您需要完整源码或者素材材料等&#xff0c;请订阅本专栏或者找博主购买&#xff01;购买后将提供源码文件…

太速科技-基于6 U VPX M.2 高带宽加固存储板

基于6 U VPX M.2 高带宽加固存储板 一、板卡概述 基于6 U VPX M.2 高带宽加固存储板&#xff0c;可以实现VPX接口的数据读写到PCI-E总线的NVME存储媒介上。采用PLX8732&#xff0c;上行链路提供带宽x16的PCI-E数据到VPX接口上&#xff1b;下行链路提供3路带宽x4的PCI-E接口…

【CSS】使用 scroll snap 实现页面的垂直大屏滚动

CSS 属性 scroll-snap-type 设置了在有滚动容器的情形下吸附至吸附点的严格程度。 scroll-snap-type 使用 scroll snap 也可以用于垂直滚动&#xff0c;全屏展示就是一个很好的例子: <main><section class"section section-1"></section><sect…