Synchronized关键字的底层原理

2023-12-05

Synchronized实现

Synchronized创建的时候一个互斥的对象锁,每次只有一个线程可以获取该锁。

其底层主要是基于 Monitor 实现的,在对象的对象头中存储了MarkWord存储的就是Monitor的地址。

对象的内存结构

对象在内存中存储主要分为三个部分:对象头,实例数据,对齐填充。

对象头:MarkWord用于存储锁的信息,Klass Word用于存储对象的类型。

  • 无锁状态:hashcode(25位)+ 对象分代年龄(4位,不是重点)+ 偏向锁标识(1位)+ 锁标识(2位)
  • 偏向锁:thread(23位,线程id)+ 偏向时间戳(2位,不是重点)+ 偏向锁标识(1位)+ 锁标识(2位)
  • 轻量级锁:对应线程的栈中指向 锁记录 的指针。(30位)
  • 重量级锁:对应monitor的地址。(30位)

实例数据:用于存储对象中成员变量的信息。

对齐填充:不是重点,主要是为了保证长度是8的整数倍。

Monitor(重量级锁)

其中包括三个部分:waitSet,entryList,owner。

owner:存储当前获得锁的线程的id。

enrtyList:存储没有获取到锁的线程id的集合,这些线程处于堵塞状态。

waitList:存储处于等待的线程的集合,通常这些线程调用了wait方法。

当线程要获取锁的时候会先去owner判断是否有线程存在,如果没有的话,直接获取锁并将线程id写入owner,反之写入entryList。

轻量级锁

重量级锁主要使用在线程竞争的时候,且重量级锁涉及进程的上下文切换,效率比较低下, 在没有线程竞争且不同线程交替执行的时候 ,推荐使用轻量级锁。

上锁

在线程栈中创建一个锁记录,锁记录中包含 锁记录地址和指向对象的指针 两个部分。 通过CAS指令将锁记录地址和MarkWord中的地址进行交换

1.如果对象处于无锁状态则说明获取锁成功,且获取的是轻量级锁。

2.如果对象已经有锁了,这此时就是 锁的重入 ,会继续创建锁记录,且也会进行 做CAS指令 ,但是

记录锁的地址为null。起到锁重入计数效果。

3.如果CAS指令失败了,则会直接使用重量级锁。

解锁

1.遍历线程栈,找到对象指针指向锁对象的锁记录。

2.如果锁记录中的MarkWord的值为null,说明这是一次锁重入操作,直接将锁记录中的指向对象的地址设置为null。

3.如果锁记录中的MarkWord的值不为null,我们就通过CAS指令将锁对象中的MarkWord恢复成无锁状态。

偏向锁

类是轻量级锁,但是在做锁的重入的时候不会使用CAS指令,而是直接判断thread的id是否相同,相同就表示没有竞争。减少了CAS指令操作。 适合使用在长时间只有一个线程使用锁

所有锁一但发生了冲突都会变成重量级锁

三种锁的使用场景

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Synchronized关键字的底层原理 的相关文章

  • 在 Eclipse 中隐藏重复的工具栏项

    我不知道如何 但我的 STS 有重复的工具栏项目 我不知道如何删除它们 这是我复制的工具栏的样子 我想摆脱这些 我试图隐藏工具栏 但这没有帮助 有人知道如何删除重复的吗 自从升级到 Oxygen 以来 我一直遇到同样的问题 我无法可靠地重现
  • 从 BroadcastReceiver 获取方法来更新 UI

    我正在尝试根据变量的变化更新用户界面BroadcastReceiver 因此 我需要调用一个扩展类的方法 以获取我提到的变量 BroadcastReceiver in MainActivity取决于但我无法以任何方式获得真正的返回值 扩展的
  • 最终字段可能尚未/已经初始化[重复]

    这个问题在这里已经有答案了 可能的重复 如何处理抛出检查异常的静态最终字段初始值设定项 https stackoverflow com questions 1866770 how to handle a static final field
  • Java:无安全管理器:RMI 类加载器已禁用

    您好 我有 RMI 应用程序 现在我尝试从客户端调用服务器上的一些方法 我有以下代码 public static void main final String args try Setting the security manager Sy
  • Apache Commons VFS - 无法解析文件

    VFS 方法无法处理此 URI jboss server temp dir local outgoing配置在jboss beans xml这是决心 C Download jboss eap 5 1 1 server default tmp
  • 限制 JPQL 中的结果数量

    如何限制从数据库检索结果的数量 select e from Entity e I need only 10 results for instance 您可以尝试像这样给出 10 个要显式获取的结果 entityManager createQ
  • 外部实体更改后索引不更新

    我目前正在开发一个项目 使用 JPA 2 1 保存数据并使用 hibernate search 4 5 0 final 搜索实体 映射类和索引后 搜索工作正常 但是 当我更改值时描述B 类从 someStr 到 anotherStr 数据库
  • 如何使用 Swipe 视图实现 Android TabLayout 设计支持库

    我将使用 android TabLayout 设计支持库 但我不知道如何使用滑动视图 这是我的代码 XML
  • 为本地@ExceptionHandler编写JUnit测试

    我有以下控制器 class Controller ResponseStatus HttpStatus OK RequestMapping value verifyCert method RequestMethod GET public vo
  • 在 Java 中的 JFrame/JPanel/JComponent 中添加 Web 浏览器

    我正在开发一个 Java 应用程序 需要在应用程序中使用 Web 浏览器 我见过一些应用程序这样做 例如在同一应用程序中单击左侧面板中的提要并打开右侧面板中的链接时的 RSS 阅读器 我想实现类似的功能 在java中可以做到这一点吗 Jav
  • Hazelcast:连接到远程集群

    我们有一组 Hazelcast 节点 全部运行在一个远程系统 具有许多节点的单个物理系统 上 我们希望从外部客户端连接到该集群 一个 Java 应用程序 它使用如下代码连接到 Hazelcast ClientConfig clientCon
  • 默认情况下,JSF 生成不可用的 ID,这些 ID 与 Web 标准的 CSS 部分不兼容

    活跃的 JSF 或 Primefaces 用户能否解释一下为什么默认情况下会发生这种情况 为什么没有人对此采取任何措施
  • 单元测试、集成测试还是设计中的问题?

    我编写了我的第一个单元测试 我认为它过于依赖其他模块 我不确定是否是因为 这是一个复杂的测试 我实际上已经编写了集成测试或 我的设计有问题 我首先要说的是 虽然我有大约 4 年的开发经验 但我从未学过 也没有人教过自动化测试 我刚刚使用 H
  • 如何加载图像文件到ImageView?

    我试图在从文件选择器中选择图像文件后立即显示该图像文件 文件选择器仅限于 png 和 jpg 文件 所选文件存储在文件类型的变量中 为此 我设置了一个 ImageView 我希望用这个新文件设置图像 唯一的问题是它的类型是文件而不是图像 如
  • SDK尚未初始化,请务必先调用FacebookSdk.sdkInitialize()

    我在实现 Facebook SDK 时遇到此错误 并且我tried https stackoverflow com questions 15490399 error inflating class com facebook widget l
  • 在片段之间切换时底部导航栏会向下推

    在我的活动中 我有一个底部导航栏和框架布局来显示片段 一切正常 但问题是当我开始按顺序从 1 4 移动时 底部导航栏保持在其位置 但当我突然从 4 跳到2 然后底部导航栏就会超出屏幕 当再次单击同一项目时 它就会回到正常位置 该视频将清楚地
  • 应用程序中空指针异常[重复]

    这个问题在这里已经有答案了 我正在尝试在我的应用程序中实施应用程序内计费 我写了这段代码 public class Settings extends PreferenceFragment ServiceConnection mService
  • 尝试使用 Spring 和扩展 Hibernate JpaRepository 的自定义 GenericDao 接口来使用 EhCache

    背景 这是我的工作 简化 GenericDao接口 由任何实现DomainDao 通用Dao java NoRepositoryBean public interface GenericDao
  • 通过向上转换将 Java.sql.date 转换为 Java.util.date 安全吗?

    java sql date 扩展了 java util date 那么通过将 java sql date 转换为 java util date 是否可以在两者之间进行转换 或者有其他方法可以转换它们吗 您不一定需要强制转换 您可以将 SQL
  • Swing:创建可拖动组件...?

    我在网上搜索了可拖动 Swing 组件的示例 但我发现示例不完整或不起作用 我需要的是一个摇摆组件那可以是dragged通过鼠标 在另一个组件内 被拖拽的时候 应该已经 改变它的位置 而不仅仅是 跳 到目的地 我很欣赏无需非标准 API 即

随机推荐