synchronized关键字以及底层实现

news2024/12/28 5:49:29

目录

基本使用

底层实现

synchronized锁升级

对象的内存结构

ⅰ. 对象头

1. ① 运行时元数据 (Mark Word) (占64位)

a. 哈希值 (HashCode)

b. GC分代年龄

c. 锁状态标记

2. ② 类型指针: (Klass Point) (占 32位)

ⅱ. 实例数据

ⅲ. 对齐填充

Moniter重量级锁

轻量级锁

偏向锁


基本使用

Java中的synchronized关键字主要用于实现线程同步,确保在多线程环境下同一时间只有一个线程可以访问被它保护的代码块或方法。以下是synchronized的基本使用方式:

1.修饰非静态方法

public class MyClass {
    private int count;

    // 一个同步实例方法
    public synchronized void increment() {
        count++;
    }
}

 在这个例子中,synchronized关键字修饰了increment()方法。这意味着任何时刻只有一个线程可以执行该方法,其他试图同时访问此方法的线程将会阻塞,直到当前线程完成方法调用并释放锁。

 2.修饰静态方法

public class MyClass {
    private static int staticCount;

    // 一个同步静态方法
    public static synchronized void incrementStatic() {
        staticCount++;
    }
}

synchronized修饰静态方法时,它锁定的是类对象(即Class级别的锁),因此,在多线程环境中,所有对该类静态方法的访问将被串行化。 

 3.修饰代码块

public class MyClass {
    private final Object lock = new Object();
    private int instanceCount;

    public void incrementInstanceCount() {
        // 同步代码块
        synchronized (lock) {
            instanceCount++;
        }
    }
}

这里synchronized用于一个代码块,它可以根据需要指定一个特定的对象作为锁对象(这里是lock对象)。只有获取到这个对象锁的线程才能进入并执行同步代码块内的内容。

底层实现

 javap -v xx.class   查看class字节码信息

synchronized关键字在Java中的底层原理主要涉及操作系统层面的互斥锁(Monitor)机制,以及JVM内部的实现细节

JVM使用monitorenter和monitorexit指令来实现对监视器的操作。

  • 当执行到monitorenter指令时,如果对象没有被锁定或者当前线程已经持有该对象的锁,则将锁计数器加1,并允许线程继续执行同步代码块。
  • 当执行到monitorexit指令时,锁计数器减1;当计数器为0时,表示锁被释放,其他等待该锁的线程可以有机会竞争获取锁并执行相应代码。

Monitor 被翻译为监视器,是由jvm提供,c++语言实现

Owner:存储当前获取锁的线程的,只能有一个线程可以获取

EntryList:关联没有抢到锁的线程,处于Blocked状态的线程

WaitSet:关联调用了wait方法的线程,处于Waiting状态的线程

synchronized锁升级

Monitor实现的锁属于重量级锁,里面涉及到了用户态和内核态的切换、进程的上下文切换,成本较高,性能比较低。

synchronized锁升级是Java 1.6及以后版本引入的一种优化机制,目的是为了在多线程环境下更好地平衡锁的性能和资源消耗。在早期版本中,Java对于synchronized关键字的实现是直接使用重量级锁(即操作系统互斥量Mutex),这种方式虽然能够确保线程安全,但其开销较大,尤其是在锁竞争不激烈的情况下。

在HotSpot虚拟机中,对象在内存中存储的布局可分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充

对象的内存结构

ⅰ. 对象头

1. ① 运行时元数据 (Mark Word) (占64位)
a. 哈希值 (HashCode)

31位的对象标识,采用延迟加载技术,调用 System.identityHashCode() 计算得到,并将结果写到对象头中,用于栈空间中,对对象的引用的指向,不然是无法找到堆中的对象的

b. GC分代年龄

(占用4位) 记录着幸存者区对象被GC过后的age, 一般age为15, 如果对象的gc次数到达了这个值,将进入老年代

c. 锁状态标记

记录加锁的一些信息

  1. hashcode:25位的对象标识Hash码
  2. age:对象分代年龄占4位
  3. biased_lock:偏向锁标识,占1位 ,0表示没有开始偏向锁,1表示开启了偏向锁
  4. thread:持有偏向锁的线程ID,占23位
  5. epoch:偏向时间戳,占2位
  6. ptr_to_lock_record:轻量级锁状态下,指向栈中锁记录的指针,占30位
  7. ptr_to_heavyweight_monitor:重量级锁状态下,指向对象监视器Monitor的指针,占30位
2. ② 类型指针: (Klass Point) (占 32位)

是对方法区中,类的元信息的引用

ⅱ. 实例数据

真实的记录一个对象包含的数据,比如Cat类对象 ,里面包含 name,age 等等相关的信息,如果有字符串,要引用字符串常量池

ⅲ. 对齐填充

仅起到占位符的作用 ,因为 HotSpot虚拟机要求对象的起始地址必须是8字节的整数,如果达不到,用对齐添充的方式补齐,为什么是8呢,因为64位的机器能被8整除,效率高

Moniter重量级锁

每个 Java 对象都可以关联一个 Monitor 对象,如果使用 synchronized 给对象上锁(重量级)之后,该对象头的Mark Word 中就被设置指向 Monitor 对象的指针

轻量级锁

在很多的情况下,在Java程序运行时,同步块中的代码都是不存在竞争的,不同的线程交替的执行同步块中的代码。这种情况下,用重量级锁是没必要的。因此JVM引入了轻量级锁的概念。

加锁流程

1.在线程栈中创建一个Lock Record,将其obj字段指向锁对象。
2.通过CAS指令将Lock Record的地址存储在对象头的mark word中,如果对象处于无锁状态则修改成功,代表该线程获得了轻量级锁。
3.如果是当前线程已经持有该锁了,代表这是一次锁重入。设置Lock Record第一部分为null,起到了一个重入计数器的作用。
4.如果CAS修改失败,说明发生了竞争,需要膨胀为重量级锁。

解锁过程

1.遍历线程栈,找到所有obj字段等于当前锁对象的Lock Record。
2.如果Lock Record的Mark Word为null,代表这是一次重入,将obj设置为null后continue。
3.如果Lock Record的 Mark Word不为null,则利用CAS指令将对象头的mark word恢复成为无锁状态。如果失败则膨胀为重量级锁。

偏向锁

轻量级锁在没有竞争时(就自己这个线程),每次重入仍然需要执行 CAS 操作。 Java 6 中引入了偏向锁来做进一步优化:只有第一次使用 CAS 将线程 ID 设置到对象的 Mark Word 头,之后发现 这个线程 ID 是自己的就表示没有竞争,不用重新 CAS。以后只要不发生竞争,这个对象就归该线程所有

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

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

相关文章

PgSQL内核特性 - push-based pipeline 执行引擎

PgSQL内核特性 - push-based pipeline 执行引擎 数据库的SQL执行引擎负责处理和执行SQL请求。通常情况下,查询优化器会输出物理执行计划,一般由一系列的算子组成。当前,有两种算子流水线构建方式:1)需求驱动的流水线&a…

板块一 Servlet编程:第二节 Servlet的实现与生命周期 来自【汤米尼克的JAVAEE全套教程专栏】

板块一 Servlet编程:第二节 Servlet的实现与生命周期 一、Servlet相关概念Serlvet的本质 二、中Web项目中实现Servlet规范(1)在普通的Java类中继承HttpServlet类(2)重写service方法编辑项目对外访问路径 二、Servlet工…

算法-4-归并排序

归并排序 public class Code01_MergeSort {// 递归方法实现public static void mergeSort1(int[] arr) {if (arr null || arr.length < 2) {return;}process(arr, 0, arr.length - 1);}// 请把arr[L..R]排有序// l...r N// T(N) 2 * T(N / 2) O(N)// O(N * logN)public …

MATLAB环境下一维时间序列信号的同步压缩小波包变换

时频分析相较于目前的时域、频域信号处理方法在分析时变信号方面&#xff0c;其主要优势在于可以同时提供时域和频域等多域信号信息&#xff0c;并清晰的刻画了频率随时间的变化规律&#xff0c;已被广泛用于医学工程、地震、雷达、生物及机械等领域。 线性时频分析方法是将信…

【知识整理】接手新技术团队、管理团队

引言 针对目前公司三大技术中心的不断升级&#xff0c;技术管理岗位要求越来越高&#xff0c;且团队人员特别是管理岗位的选择任命更是重中之重&#xff0c;下面针对接手新的技术团队做简要整理&#xff1b; 一、实践操作 1、前期准备 1、熟悉情况&#xff1a; 熟悉人员&am…

VTK 三维场景的基本要素(相机) vtkCamera

观众的眼睛好比三维渲染场景中的相机&#xff0c;在VTK中用vtkCamera类来表示。vtkCamera负责把三维场景投影到二维平面&#xff0c;如屏幕&#xff0c;相机投影示意图如下图所示。 1.与相机投影相关的要素主要有如下几个&#xff1a; 1&#xff09;相机位置: 相机所处的位置…

锐捷(十九)锐捷设备的接入安全

1、PC1的IP地址和mac地址做全局静态ARP绑定; 全局下&#xff1a;address-bind 192.168.1.1 mac&#xff08;pc1&#xff09; G0/2:ip verify source port-securityarp-check 2、PC2的IP地址和MAC地址做全局IPMAC绑定&#xff1a; Address-bind 192.168.1.2 0050.7966.6807Ad…

立体视觉几何 (三)

立体视觉系统概述 误差分析 考虑对应于深度 Z 的视差 d 的匹配对。我们想要评估 ΔZ&#xff0c;即视差误差引起的深度误差。将 Z 对 d 求导&#xff0c;得到&#xff1a; 立体视觉中基线&#xff08;baseline&#xff09;、焦距&#xff08;focal length&#xff09;和立体重…

【数据结构】11 堆栈(顺序存储和链式存储)

定义 可认为是具有一定约束的线性表&#xff0c;插入和删除操作都在一个称为栈顶的端点位置。也叫后入先出表&#xff08;LIFO&#xff09; 类型名称&#xff1a;堆栈&#xff08;STACK&#xff09; 数据对象集&#xff1a; 一个有0个或者多个元素的有穷线性表。 操作集&#…

Failed to parse multipart servlet request; nested exception is java.io.IOException,文件上传异常的问题如何解决

背景:有时候我们上传文件时会遇到这种报错,"Failed to parse multipart servlet request; nested exception is java.io.IOException: The temporary upload location [C:\\Users\\XXXX\\AppData\\Local\\Temp\\tomcat.2460390372185321891.8082\\work\\Tomcat\\localho…

EXCEL函数学习之FREQUENCY函数

如下图&#xff0c;要统计各分数段的人数。 同时选中E2:E6&#xff0c;输入以下公式&#xff0c;按住ShiftCtrl不放&#xff0c;按回车。 FREQUENCY(B2:B11,D2:D5) FREQUENCY函数计算数值在某个区域内的出现频次&#xff0c;这个函数的用法为&#xff1a; FREQUENCY(要统计的…

grab,一个强大的 Python 库!

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个强大的 Python 库 - grab。 Github地址&#xff1a;https://github.com/lorien/grab Python Grab 是一个功能强大的 Web 抓取框架&#xff0c;它提供了丰富的功能和灵活的接口&#xff0c;使得…

寒假思维训练day20

更新一道1600的反向贪心 题意&#xff1a; 有n场比赛&#xff0c;且小明的智商是m&#xff0c;每场比赛需要的智商是,当时, 可以直接看题&#xff0c;当时&#xff0c;需要智商m减1才能看这道题&#xff0c;当智商为0不能继续往下看题&#xff0c;问最多能看多少题 题解&#x…

《UE5_C++多人TPS完整教程》学习笔记9 ——《P10 创建会话(Creating A Session)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P10 创建会话&#xff08;Creating A Session&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&#xff08;也是译者&…

C++学习笔记 | 基于Qt框架开发实时成绩显示排序系统1

目标&#xff1a;旨在开发一个用户友好的软件工具&#xff0c;用于协助用户基于输入对象的成绩数据进行排序。该工具的特色在于&#xff0c;新输入的数据将以红色高亮显示&#xff0c;从而直观地展现出排序过程中数据变化的每一个步骤。 结果展示&#xff1a; 本程序是一个基于…

2024刘谦春晚第二个扑克牌魔术

前言 就是刚才看春晚感觉这个很神奇&#xff0c;虽然第一个咱模仿不过来&#xff0c;第二个全国人民这么多人&#xff0c;包括全场观众都有成功&#xff0c;这肯定是不需要什么技术&#xff0c;那我觉得这个肯定就是数学了&#xff0c;于是我就胡乱分析一通。 正文 首先准备…

华为问界M9:领跑未来智能交通的自动驾驶黑科技

华为问界M9是一款高端电动汽车&#xff0c;其自动驾驶技术是该车型的重要卖点之一。华为在问界M9上采用了多种传感器和高级算法&#xff0c;实现了在不同场景下的自动驾驶功能&#xff0c;包括自动泊车、自适应巡航、车道保持、自动变道等。 华为问界M9的自动驾驶技术惊艳之处…

电商小程序04实现登录逻辑

目录 1 创建自定义方法2 获取用户名和密码3 验证用户是否同意协议4 验证用户名和密码总结 上一篇我们实现了登录功能的前端界面&#xff0c;这一篇实现一下登录的具体逻辑。 1 创建自定义方法 一般如果页面点击按钮需要有事件响应的&#xff0c;我们用自定义方法来实现。打开我…

【Linux系统学习】5.Linux实用操作 下

7.虚拟机配置固定IP 7.1 为什么需要固定IP 当前我们虚拟机的Linux操作系统&#xff0c;其IP地址是通过DHCP服务获取的。 DHCP&#xff1a;动态获取IP地址&#xff0c;即每次重启设备后都会获取一次&#xff0c;可能导致IP地址频繁变更 原因1&#xff1a;办公电脑IP地址变化无所…

第77讲用户管理功能实现

用户管理功能实现 前端&#xff1a; views/user/index.vue <template><el-card><el-row :gutter"20" class"header"><el-col :span"7"><el-input placeholder"请输入用户昵称..." clearable v-model"…