synchronized 的底层原理

news2024/11/25 12:36:41

tip: 作为程序员一定学习编程之道,一定要对代码的编写有追求,不能实现就完事了。我们应该让自己写的代码更加优雅,即使这会费时费力。

文章目录

  • 一、synchronized 的底层原理
  • 二、synchronized 的锁升级原理
    • 1、偏向锁
    • 2、轻量级锁
    • 3、重量级锁

一、synchronized 的底层原理

synchronized 的底层是通过 Java 中的**监视器锁(monitor)**来实现的。每个 Java 对象都有一个与之对应的监视器锁,当一个线程获取了该对象的监视器锁,就可以执行 synchronized 代码块或方法。其他线程只能等待该线程释放锁,才能获取该对象的监视器锁并执行 synchronized 代码块或方法。

在 Java 中,每个对象都有一个与之关联的管程(monitor)。管程包括两个部分:一个是对象头(Object Header),用于存储对象的元数据信息;另一个是监视器锁(Monitor Lock),用于实现线程同步。当一个线程获取了对象的监视器锁,就可以执行 synchronized 代码块或方法,其他线程只能等待该线程释放锁,才能获取该对象的监视器锁并执行 synchronized 代码块或方法。

当一个线程进入 synchronized 代码块或方法时,它会尝试获取对象的监视器锁。如果该锁没有被其他线程占用,则该线程获取锁并继续执行 synchronized 代码块或方法;如果该锁已经被其他线程占用,则该线程会进入锁池(Lock Pool)等待,直到该锁被其他线程释放。

当一个线程释放对象的监视器锁时,它会唤醒锁池中的一个等待线程,让其获取锁并继续执行 synchronized 代码块或方法。如果锁池中有多个等待线程,那么唤醒哪个线程是不确定的,取决于 JVM 的实现。

二、synchronized 的锁升级原理

synchronized 的锁升级指的是在不同的情况下,synchronized 锁的状态会从偏向锁、轻量级锁、重量级锁等级别逐步升级的过程。在 Java 6 及之前的版本中,synchronized 的锁升级过程是固定的,而在 Java 6 及之后的版本中,锁升级过程是根据当前锁的状态和竞争情况动态调整的。

偏向锁:当一个线程访问同步块并获取锁时,会在对象头中记录锁偏向的线程 ID,以后该线程再次进入同步块时,只需判断当前线程 ID 是否与对象头中记录的线程 ID 相同,如果相同,就可以直接进入同步块,无需进行额外的同步操作。如果有其他线程竞争锁,则偏向锁会被撤销。

轻量级锁:当一个线程获取锁失败时,会尝试使用轻量级锁来提高性能。轻量级锁是通过将对象头中的信息复制到线程的栈帧中,然后在栈帧中进行同步操作来实现的。如果在同步过程中发生竞争,则轻量级锁会升级为重量级锁。

重量级锁:当多个线程竞争同一个锁时,会升级为重量级锁。重量级锁是通过操作系统的互斥量来实现的,每次加锁和释放锁都需要进行系统调用,开销较大。

在 Java 6 及之前的版本中,锁升级过程是固定的,即从偏向锁升级到轻量级锁,再升级到重量级锁。而在 Java 6 及之后的版本中,锁升级过程是根据当前锁的状态和竞争情况动态调整的,可以根据实际情况选择偏向锁、轻量级锁或重量级锁,从而提高程序的性能。

1、偏向锁

偏向锁是 Java 中的一种锁优化机制。它的主要目的是减少无竞争情况下的同步操作,从而提高程序的性能。在偏向锁的情况下,当一个线程访问同步块并获取锁时,会在对象头中记录锁偏向的线程 ID,以后该线程再次进入同步块时,只需判断当前线程 ID 是否与对象头中记录的线程 ID 相同,如果相同,就可以直接进入同步块,无需进行额外的同步操作。

偏向锁的优点是可以减少同步操作的开销,尤其是在无竞争的情况下。在无竞争的情况下,偏向锁可以避免多余的同步操作,从而提高程序的性能。另外,偏向锁的实现比较简单,开销也比较小。

偏向锁的缺点是当有其他线程竞争锁时,偏向锁会被撤销,这样就会导致额外的同步操作,从而降低程序的性能。此外,偏向锁只适用于无竞争的情况,如果存在竞争,就需要使用其他的锁机制来保证线程安全。

需要注意的是,偏向锁只适用于单线程访问同步块的情况。如果多个线程访问同一个同步块,就会出现竞争,此时偏向锁会被撤销,从而降低程序的性能。

package com.pany.camp.lock;

import org.openjdk.jol.info.ClassLayout;

public class BiasedLockDemo {

    public static void main(String[] args) throws InterruptedException {
        BiasedLockDemo biasedLockDemo = new BiasedLockDemo();
        biasedLockDemo.doSomething();
        System.out.println(ClassLayout.parseInstance(biasedLockDemo).toPrintable());
    }

    public synchronized void doSomething() {
        System.out.println("doSomething() is called");
    }
}

在这里插入图片描述
在上面的输出中,我们可以看到对象头中的第一个字节是 01 ,这个字节的二进制表示是 00000001 ,其中第0位是1,表示这个对象的锁是偏向锁。如果第0位是0,表示这个对象的锁不是偏向锁。

可以通过 -xx:UseBiasedLocking 禁用偏向锁。

2、轻量级锁

轻量级锁是Java虚拟机为了提高多线程程序性能而引入的一种锁优化机制。与传统的重量级锁相比,轻量级锁的锁操作使用了更加轻量级的机制,避免了不必要的线程阻塞和上下文切换,从而提高了多线程程序的执行效率。

轻量级锁的实现原理是,当一个线程第一次进入同步代码块时,Java虚拟机会为该对象分配一个锁记录(Lock Record)并将对象头中的Mark Word复制到锁记录中。然后,虚拟机会尝试使用CAS操作将对象头中的Mark Word替换为指向锁记录的指针,从而将对象的锁状态升级为轻量级锁。如果CAS操作成功,该线程就可以继续执行同步代码块,否则就会退化为重量级锁,从而保证线程安全。

当一个线程持有轻量级锁时,其他线程可以使用CAS操作来尝试获取锁。如果获取成功,就可以继续执行同步代码块。如果获取失败,就会进入自旋状态,等待持有锁的线程释放锁。如果自旋次数超过一定阈值,或者持有锁的线程被阻塞,就会退化为重量级锁。

总之,轻量级锁是Java虚拟机为了提高多线程程序性能而引入的一种锁优化机制,它避免了不必要的线程阻塞和上下文切换,从而提高了多线程程序的执行效率。

package com.pany.camp.lock;

import cn.hutool.core.thread.ThreadUtil;
import org.openjdk.jol.info.ClassLayout;

public class LightLock {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public static void main(String[] args) {
        final LightLock obj = new LightLock();
        final int numThreads = 5;
        final int numIterations = 10000;

        Thread t1 = new Thread(() -> {
            ThreadUtil.sleep(1000);
            System.out.println(ClassLayout.parseInstance(obj).toPrintable());
        }, "t1");
        t1.start();

        // 创建多个线程并启动
        Thread[] threads = new Thread[numThreads];
        for (int i = 0; i < numThreads; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < numIterations; j++) {
                    // 对共享对象加锁
                    synchronized (obj) {
                        obj.increment();
                        ThreadUtil.sleep(1);
                    }
                }
            });
            threads[i].start();
        }


        System.out.println("Count: " + obj.count);
    }
}


在这里插入图片描述
上面的例子,对象头的 Mark Word 已经替换为指向锁记录的指针,已经升级成轻量级锁了。

3、重量级锁

重量级锁是Java中的一种锁机制,也称为互斥锁。它是基于操作系统的互斥量实现的,需要进行用户态与内核态之间的切换,因此开销比较大,效率较低。当多个线程竞争同一个锁时,如果该锁是重量级锁,那么线程会进入阻塞状态,等待锁的释放。在Java中,synchronized关键字使用的锁就是重量级锁。

重量级锁的实现原理是,在Java虚拟机中,每个对象都与一个监视器关联,当一个线程需要获取该对象的锁时,它会尝试获取该对象的监视器锁。如果该锁已经被其他线程持有,那么该线程就会进入阻塞状态,等待锁的释放。当该锁被释放时,等待队列中的线程会被唤醒,并重新尝试获取锁。

重量级锁的优点是实现简单,可靠性高,不会出现死锁等问题。缺点是由于需要进行用户态与内核态之间的切换,因此开销比较大,效率较低。在多线程环境下,如果使用重量级锁过多,会导致系统性能下降,因此应该根据具体情况选择合适的锁机制。

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

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

相关文章

大幅提升iOS编译速度的cocoapods二进制化插件介绍

1. 背景 驾校一点通iOS项目是采用是cocoapods来管理组件的&#xff0c;又经过多年的组件化发展&#xff0c;目前组件已经达到了120的数量。在这种组件规模下&#xff0c;主工程的打包时间也从最开始的几分钟增加到十几分钟&#xff08;M1&#xff09;、二十几分钟&#xff08;…

restTemplate转发Https请求

代码架构 package com.http.controller;import com.http.RestTemplateConfig; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework…

Vercel部署个人博客

vercel 部署静态资源网站极其方便简单&#xff0c;并且有可观的访问速度&#xff0c;最主要的是免费部署。 如果你还没有尝试的话&#xff0c;强烈建议去使用一下。 演示博客演示http://202271.xyz/?vercel vercel 介绍 注册账号 进入Vercel官网https://vercel.com&#x…

Android studio安装教程(图文详解,简单搞定)

一 下载 根据自己计算机选择对应版本点击下载 https://developer.android.google.cn/studio 二 安装Android Studio Android Studio 是Google提供的一个Android开发环境&#xff0c;基于IntelliJ IDEA类似 Eclipse ADT&#xff0c;他集成了Android 所需的开发工具。需要注意…

RocketMq的集群的搭建(2主2从异步复制集群模式)

一 RocketMq集群搭建 1.1 说明 本案例采用2m-2s-async的方式搭建集群。 实际项目中&#xff0c;为了达到高可用&#xff0c;一般会使用dleger。 https://blog.csdn.net/wssc63262/article/details/126003507 1.2 集群规划说明 集群规划说明&#xff1a; nameserver是一个…

机器学习——集成学习(装袋法Bagging、提升法Boosting、梯度提升决策树GBDT、随机森林RF)

集成学习 集成学习通过构建并结合多个学习器来完成学习任务 集成方法是用多种学习方法的组合来获取比原方法更优的结果 使用于组合的算法是弱学习算法 即分类正确率仅比随机猜测略高的学习算法 但是组合之后的效果仍可能高于强学习算法 即集成之后的算法准确率和效率都很高…

# 车载软件架构 —— 闲聊几句AUTOSAR OS(三)

我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 没有人关注你。也无需有人关注你。你必须承认自己的价值,你不能站在他人的角度来反对自己。人生在世,最怕的就是把别人的眼光当成自己生活的唯一标准。到最…

程序员从0到收获心仪offer,我靠训练营实现了180度逆袭!

我相信&#xff0c;在未来的职场中&#xff0c;我也能通过这段时间养成的学习习惯和生活习惯让自己一步步成为更好的自己&#xff0c;以自己为荣 我在大学里主修计算机科学与技术&#xff0c;一个普通的院校&#xff0c;一个算是常见的专业&#xff0c;我知道我的学历和一些其他…

Tomcat的部署(贼详细)

目录 一、Tomcat服务器简介 1、Tomcat服务器 2、Tomcat三大核心组件 3、 Java Servlet 4、JSP全称Java Server Pages 5、 Tomcat 功能组件结构 6、 Container 结构分析 7、Tomcat 请求过程 二&#xff1a;Tomcat部署与安装 1.关闭防火墙&#xff0c;上传所需软件包 2.安…

前端、后端工程师学习路线

学习的平台推荐 视频平台&#xff1a; 慕课&#xff1a;http://www.imooc.com/ 腾讯课堂&#xff1a;https://ke.qq.com/ 教程平台 菜鸟&#xff1a;https://www.runoob.com/ W3&#xff1a;https://www.w3school.com.cn/ yibai&#xff1a;https://www.yiibai.com/ 前端学习路…

c++—STL(六大组件)

一、STL概述 1. STL概述 &#xff08;1&#xff09;STL定义&#xff1a;STL&#xff08;standard template library&#xff09;&#xff0c;标准模板库&#xff0c;是一个高效的c程序库&#xff0c;重在提高了代码的复用性&#xff1b;主要包含了常用的数据结构和基本算法&am…

一分钟学一个 Linux 命令 - mkdir 和 touch

前言 大家好&#xff0c;我是god23bin。欢迎来到《一分钟学一个 Linux 命令》系列&#xff0c;今天需要你花两分钟时间来学习下&#xff0c;因为今天要讲的是两个命令&#xff0c;mkdir 和 touch 命令。前一个命令是操作目录的&#xff0c;后一个命令是操作文件的。 建议学完手…

蓝桥杯STC15F2K60S2单片机 CCP/PCA/PWM模块的学习与使用

有道是“一花独放不是春&#xff0c;万紫千红春满园” 我们不能只满足于 眼前所谓的 “够用、能用” 的少量知识&#xff0c;而不去深入学习探究&#xff0c;进而不慎封锁了自己的见识 和 更多 创新开发上的可能性。 曾经仅满足于学习了蓝桥杯单片机的三个外部晶振 定时器&am…

日撸java三百行day58-59

文章目录 说明Day58 符号型数据的 NB 算法1.基础理论知识1.1 条件概率1.2 独立性假设1.3 Laplacian 平滑 2. 符号型数据的预测算法跟踪2.1 testNominal()方法2.1.1 NaiveBayes 构造函数2.1.2 calculateClassDistribution()2.1.3 calculateConditionalProbabilities()方法2.1.4 …

D*算法详解 (D星算法 / Dynamic A*算法/ Dstar算法)(死循环解决)【编辑中】

所需先验知识&#xff08;没有先验知识可能会有大碍&#xff0c;了解的话会对D*的理解有帮助&#xff09;&#xff1a;A*算法/ Dijkstra算法 何为D*算法 Dijkstra算法是无启发的寻找图中两节点的最短连接路径的算法&#xff0c;A*算法则是在Dijkstra算法的基础上加入了启发函数…

【linux下一次复制cp多个文件】

linux下一次复制cp多个文件 linux cp 参数说明 -a&#xff1a;此选项通常在复制目录时使用&#xff0c;它保留链接、文件属性&#xff0c;并复制目录下的所有内容。其作用等于dpR参数组合。 -d&#xff1a;复制时保留链接。这里所说的链接相当于Windows系统中的快捷方式。 -f&…

使用可上网的服务器作为网关,实现另一台服务器上网

文章目录 物理条件方法一&#xff1a;不使用交换机方法二&#xff1a;使用交换机 配置步骤查看网络状态设置静态IP将服务器A设置成网关重新启动各服务器网卡设置主机名 参考资料 本文的目标是利用一台可以上网的服务器作为网关&#xff0c;使在同一局域网中的所有服务器都可以上…

如何安装多个node版本(不使用nvm)

1、选择node安装的路径 例如&#xff1a;D:\Program Files\nodejs 2、下载要安装的对应版本的zip格式的node安装包 例如&#xff1a;下载16.14.2 和 13.14.0 两个版本的zip格式的node安装包&#xff0c;node版本下载地址https://nodejs.org/dist/ 3、安装包解压到对应文件夹…

遥感云大数据在灾害、水体与湿地领域典型

近年来遥感技术得到了突飞猛进的发展&#xff0c;航天、航空、临近空间等多遥感平台不断增加&#xff0c;数据的空间、时间、光谱分辨率不断提高&#xff0c;数据量猛增&#xff0c;遥感数据已经越来越具有大数据特征。遥感大数据的出现为相关研究提供了前所未有的机遇&#xf…

路径规划算法:基于JAYA优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于JAYA优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于JAYA优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法JAYA…