synchronized的实现原理和锁升级 面试重点

1.synchronized的实现原理

        synchronized是Java 中的一个很重要的关键字,主要用来加锁,synchronized所添加的锁有以下几个特点。synchronized的使用方法比较简单,主要可以用来修饰方法和代码块。根据其锁定的对象不同,可以用来定义同步方法和同步代码块。
        方法级的同步是隐式的(同步方法)。同步方法的常量池中会有一个ACC_SYNCHRONIZED标志。当某个线程要访问某个方法的时候,会检查是否有ACC_SYNCHRONIZED,如果有设置,则需要先获得监视器锁,然后开始执行方法,方法执行之后再释放监视器锁。这时如果其他线程来请求执行方法,会因为无法获得监视器锁而被阻断住。值得注意的是,如果在方法执行过程中,发生了异常,并且方法内部并没有处理该异常,那么在异常被抛到方法外面之前监视器锁会被自动释放。
        同步代码块使用monitorenter和monitorexit两个指令实现。 可以把执行monitorenter指令理解为加锁,执行monitorexit理解为释放锁。 每个对象维护着一个记录着被锁次数的计数器。未被锁定的对象的该计数器为0,当一个线程获得锁(执行 monitorenter)后,该计数器自增变为 1,当同一个线程再次获得该对象的锁的时候,计数器再次自增。当同一个线程释放锁(执行monitorexit指令)的时候,计数器再自减。当计数器为0的时候。锁将被释放,其他线程便可以获得锁。

2.synchronized特性

synchronized是Java中的一个很重要的关键字,主要用来加锁,synchronized具有以下特性:
互斥性
       同一时间点,只有一个线程可以获得锁,获得锁的线程才可以处理被 synchronized 修饰的代码片段。
阻塞性
        只有获得锁的线程才可以执行被synchronized 修饰的代码片段,未获得锁的线程只能阻塞,等待锁释放。
可重入性
        如果一个线程已经获得锁,在锁未释放之前,再次请求锁的时候,是必然可以获得锁的

3.锁的具体表现:

        对于普通同步方法,锁是当前 象。
        对于静 同步方法, 是当前 Class 象。
        对于同步方法 Synchonized 括号里配置的 象。

4.monitor(监视锁)

为了解决线程安全的问题,Java提供了同步机制、互斥锁机制,这个机制保证了在同一时刻只一个线程能访问共享资源。
        这个机制的保障来源于监视锁Monitor,每个对象都拥有自己的监视锁Monitor。当我们尝试获得对象的锁的时候,其实是对该对象拥有的Monitor 进行操作。

5.synchronized锁的是什么?

无论是给静态方法或者非静态方法,加上synchronized标识,都是锁的对象,synchronized的普通方法,其实锁的是具体调用这个方法的实例对象,而synchronized的静态方法,其实锁的是这个方法锁属于的类对象。

6.synchronized的锁升级过程是怎样的?

6.1为什么要锁升级?
在JDK1.6及之前的版本中,synchronized锁是通过对象内部的一个叫做监视器锁(也称对象锁)来实现的。当一个线程请求对象锁时,如果该对象没有被锁住,线程就会获取锁并继续执行。如果该对象已经被锁住,线程就会进入阻塞状态,直到锁被释放。这种锁的实现方式称为“重量级锁”,因为获取锁和释放锁都需要在操作系统层面上进行线程的阻塞和唤醒,而这些操作会带来很大的开销。
        在JDK 1.6之后,synchronized锁的实现发生了一些变化,引入了“偏向锁”、“轻量级锁”和“重量级锁”三种不同的状态,用来适应不同场景下的锁竞争情况。
所以,在Java中,锁的状态分为四种,分别是无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态。
6.2 不同锁状态下的对象头中 mark word结构
在Java中,mark word的低两位用于表示锁的状态,分别为“01”(无锁状态)、“01”(偏向锁状态)、“00”(轻量级锁状态)和“10"(重量级锁状态)。但是由于无锁状态和偏向锁都是“01”,
所以在低三位引入偏向锁标记位,用“0“表示无锁,“1“表示偏向。
6.3 偏向锁
        大多数情况下,锁 不存在多 线 争,而且 是由同一线 程多次 得, 让线 的代价更低而引入了偏向 。当一个 线 访问 同步 并获取 锁时 ,会在 栈帧 中的 锁记录 里存 储锁 偏向的 线 ID ,以后 该线 程在 入和退出同步块时 不需要 CAS 操作来加 和解 ,只需 简单 测试 一下 Mark Word 里是否存储 着指向当前 线 程的偏向 。如果 测试 成功,表示 线 程已 经获 得了 。如果 测试 需要再测试 一下 Mark Word 中偏向 标识 是否 置成 1 (表示当前是偏向 ):如果没有 置, 则使用CAS ;如果 置了, 则尝试 使用 CAS 的偏向 指向当前 线 程。
触发条件:首次进入synchronized块是自动开启。
6.3.1偏向的撤
        偏向锁 使用了一种等到 争出 的机制,所以当其他 线 尝试竞 争偏向 锁时, 持有偏向锁 线 程才会 。偏向 的撤 ,需要等待全局安全点(在 时间 点上没有正在执 行的字 节码 )。它会首先 有偏向 线 程,然后 检查 持有偏向 线 程是否活着,如果线 程不 于活 头设 置成无 ;如果 线 程仍然活着, 有偏向 栈会被执 行,遍 偏向 象的 锁记录 中的 锁记录 Mark Word 要么重新偏向于其他线程,要么恢复到无 或者 标记对 象不适合作 偏向 ,最后 停的 线 程。
6.4 轻量级锁
(1)轻量级加锁
        线程在 行同步 之前, JVM 会先在当前 线 程的 栈桢 建用于存 储锁记录 的空 ,并将对 中的 Mark Word 复制到 锁记录 中,官方称 Displaced Mark Word 。然后 线 尝试 使用CAS将 中的 Mark Word 换为 指向 锁记录 的指 。如果成功,当前 线 ,如果失败,表示其他 线 ,当前 线 程便 尝试 使用自旋来
2级锁
        轻量 锁时 ,会使用原子的 CAS 操作将 Displaced Mark Word 回到 ,如果成
功, 表示没有 生。如果失 ,表示当前 存在 争, 就会膨 成重量 级锁
6.5 重量级锁
当轻量级锁的CAS操作失败,即出现了实际的竞争,锁会进一步升级为重量级锁。当锁状态升级到重量级锁状态时,JVM会将该对象的锁变成一个重量级锁,并在对象头中记录指向等待队列的指针。
        此时,如果一个线程想要获取该对象的锁,则需要先进入等待队列,等待该锁被释放。当锁被释放时,JVM 会从等待队列中选择一个线程唤醒,并将该线程的状态设置为“就绪”状态,然后等待该线程重新获取该对象的锁。
触发条件:当轻量级锁的CAS操作失败,轻量级锁升级为重量级锁。
        因为 自旋会消耗 CPU 了避免无用的自旋(比如 线 程被阻塞住了),一旦 级 成重量级锁 ,就不会再恢复到 级锁 。当 锁处 个状 下,其他 线 试图获 锁时 ,都会被阻塞住,当持有锁 线 之后会 线 程,被 醒的 线 程就会 行新一 轮的夺锁 之争。
6.6 锁的优缺点对比

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

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

相关文章

生命周期的妙用——Vue3

Vue3的生命周期 从Vue2到Vue3👾不只onMounted又见keep-alive主要属性被你包裹应用场景 ) 从Vue2到Vue3👾 Vue 3 保留了大多数 Vue 2 的生命周期钩子,同时引入了组合 API 中的生命周期钩子。以下是 Vue 3 中的生命周期钩子: 不…

数据库管理的艺术(MySQL):DDL、DML、DQL、DCL及TPL的实战应用(下:数据操作与查询)

文章目录 DML数据操作语言1、新增记录2、删除记录3、修改记录 DQL数据查询语言1、查询记录2、条件筛选3、排序4、函数5、分组条件6、嵌套7、模糊查询8、limit分页查询 集合操作union关键字和运算符in关键字any关键字some关键字all关键字 联合查询1、广义笛卡尔积2、等值连接3、…

HTML+JS+CSS计算练习

可填 题目数量 数字范围 计算符号 题目做完后会弹窗提示正确率、用时 效果图 源代码在图片后面 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevic…

【深度学习】inpaint图像中的alpha混合图的边缘处理

比如原图是&#xff1a; 红圈内就是文字水印&#xff0c;经过inpaint后得到图和原图混合&#xff0c;如何处理边界呢&#xff0c;这个代码可以干这事&#xff1a; 越是中心就直接用inpaint图&#xff0c;否则就用原图&#xff0c;这样进行alpha混合。 import numpy as np i…

js reduce 的别样用法

let mergedItems list.reduce((accumulator, currentItem) > {let existingItem accumulator.find((item) > item.manObject_name currentItem.manObject_name);if (existingItem) {existingItem.laborCostHand currentItem.laborCostHand; //劳务费existingItem.wor…

windows下使用make编译C/C++程序 gcc编译 MinGW编译器

文章目录 1、概要2、编译环境搭建3、创建工程目录结构4、 编写程序4.1 编写头文件4.2 编写源文件 5、编写makefile及相关文件5.1 编写清理编译生成文件的批处理文件&#xff0c;供makefile调用5.2 编写makefile文件 6、编译工程6.1 打开命令行6.2 使用make命令编译程序6.3 编译…

effective c++学习笔记1

Effective C 来源于阿西拜编程 《Effective C》2023&#xff08;上部完整版&#xff09; C进阶看这个_哔哩哔哩_bilibili 2024年7月15日 第一章 第1条 第7章&#xff0c;学完比较能够看懂&#xff0c;一般公司不推荐写模板&#xff08;调试麻烦&#xff0c;维护成本高&…

Anaconda创建新的环境一直报错

Anaconda创建新的环境一直报错 报错信息如下&#xff1a; CondaHTTPError: HTTP 404 NOT FOUND for url <https://pypi.tuna.tsinghua.edu.cn/simple/noarch/repodata.json> Elapsed: 00:01.358961The remote server could not find the noarch directory for the requ…

你的字典还是想改就改?试试Python MappingProxyType,让你的数据只读到底!

目录 1、初识MappingProxyType &#x1f50d; 1.1 MappingProxyType简介 1.2 不可变映射的优势 2、创建你的第一个MappingProxyType实例 &#x1f389; 2.1 使用dict创建MappingProxyType 2.2 获取MappingProxyType属性 3、探索MappingProxyType的方法和属性 &#x1f6…

HarmonyOS NEXT零基础入门到实战-第一部分

构建节页面思路&#xff1a; 1、排版 (分析布局) 2、内容&#xff08;基础组件&#xff09; 3、美化&#xff08;属性方法&#xff09; 设计资源-svg图标 界面中展示图标 ->可以使用svg图标&#xff08;任意放大缩小不失真&#xff0c;可以改颜色&#xff09; 使用方式&a…

Linux内核分析:VFS和文件系统

文章目录 写在前面下载链接思维导图一些问题使用slab进行分配的优势和意义如何理解这段话&#xff1a;Linux 将新的文件系统通过一个称为“挂装”或“挂上”的操作将其挂装到某个目录上&#xff0c;从而让不同的文件系统结合成为一个整体。Linux 操作系统的一个重要特点是它支持…

apisix安装

安装依赖 如果当前系统没有安装 OpenResty&#xff0c;请使用以下命令来安装 OpenResty 和 APISIX 仓库&#xff1a; sudo yum install -y https://repos.apiseven.com/packages/centos/apache-apisix-repo-1.0-1.noarch.rpm如果已安装 OpenResty 的官方 RPM 仓库&#xff0c…

Clonezilla 备份还原过程推送日志到 syslog

Clonezilla 备份、还原过程中&#xff0c;系统的运行日志只能显示到客户端显示器上&#xff0c;如果出现错误&#xff0c;无法在服务端查询到对应的日志&#xff0c;一是故障判断不太方便&#xff1b;另一方面&#xff0c;实现日志推送&#xff0c;也可以将 Clonezilla 运行进度…

配置和保护SSH

使用SSH访问远程命令行 描述Secure Shell SSH&#xff08;Secure Shell&#xff09; 是一种网络协议&#xff0c;用于在不安全的网络上安全地进行系统管理和数据传输。它最初由 Tatu Ylnen 于1995年设计&#xff0c;并成为保护网络服务免受攻击的标准。SSH提供了多种功能&…

正则表达式(Ⅳ)——零宽断言

介绍 以……为开头/以……为结尾 正向表示匹配白名单 先行表示需要写在想要筛选的表达式之后 负向表示匹配黑名单 后行表示需要写在想要筛选的表达式之前 正向先行断言 这段比较复杂&#xff0c;我们拆开来看 \d(?PM) \d表示匹配数字&#xff0c;而且是匹配单个数字 表示…

【C++】C++ 职工信息管理系统(源码)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

EXCEL的自定义功能

一、Excel文件获取 OFFICE中导入文本文件&#xff0c;CSV&#xff08;分隔符通常是逗号&#xff09;和TXT&#xff08;分隔符通常是Tab键&#xff0c;可以用记事本打开查看分隔符&#xff09;进入单元格&#xff0c;数据——获取外部数据——自文本。 WPS中数据——获取数据——…

Java学习高级四

JDK8开始&#xff0c;接口新增了三种形式的方法 接口的多继承 内部类 成员内部类 静态内部类 局部内部类 匿名内部类 import javax.swing.*; import java.awt.event.ActionEvent;public class Test {public static void main(String[] args) {// 扩展 内部类在开发中的真实使用…

408一战130+|暑假四门课复习经验+资料分享

刚好我有点发言权 408想要考高分&#xff0c;其实很简单&#xff0c;学会抓住主要矛盾&#xff01; 是吗是主要矛盾&#xff0c;大家都知道&#xff0c;408学科四门课&#xff0c;分别是数据结构&#xff0c;计算机组成原理&#xff0c;操作系统&#xff0c;计算机网络。那么4…

Python进阶(4)--正则表达式

正则表达式 在Python中&#xff0c;正则表达式&#xff08;Regular Expression&#xff0c;简称Regex&#xff09;是一种强大的文本处理工具&#xff0c;它允许你使用一种特殊的语法来匹配、查找、替换字符串中的文本。 在这之前&#xff0c;还记得之前我们是通过什么方法分割…