深圳品牌网站制作/免费正能量erp软件下载

深圳品牌网站制作,免费正能量erp软件下载,好玩的游戏,wordpress首页链接文章目录 一、 synchronized 关键字二、Java对象结构1. 对象头2. 对象体3. 对齐字节4. 对象头中的字段长度5. Mark Word 的结构信息6. 使用 JOL 工具查看对象的布局 三、Java 内置锁机制3.1 内置锁的演进过程1. 无锁状态2. 偏向锁状态3. 轻量级锁状态4. 重量级锁状态 一、 sync…

文章目录

  • 一、 synchronized 关键字
  • 二、Java对象结构
    • 1. 对象头
    • 2. 对象体
    • 3. 对齐字节
    • 4. 对象头中的字段长度
    • 5. Mark Word 的结构信息
    • 6. 使用 JOL 工具查看对象的布局
  • 三、Java 内置锁机制
    • 3.1 内置锁的演进过程
      • 1. 无锁状态
      • 2. 偏向锁状态
      • 3. 轻量级锁状态
      • 4. 重量级锁状态

一、 synchronized 关键字

在Java中,synchronized关键字通过内置锁(也称为监视器锁或互斥锁)机制实现线程间的互斥访问。具体来说,它确保在同一时刻只有一个线程能够执行特定的同步代码块或方法。

  1. Java内置锁

每个对象都有一个与之关联的内置锁(monitor lock)。当一个线程进入synchronized方法或代码块时,它会尝试获取该对象的内置锁。如果成功获取到锁,则该线程可以继续执行;否则,线程将被阻塞并放入等待队列中,直到锁被释放。

  1. 锁的状态
  • 无锁状态:对象处于未锁定状态,任何线程都可以尝试获取该对象的锁。

  • 偏向锁状态:JVM优化的一种方式,在几乎没有竞争的情况下,锁会偏向于第一个获取它的线程,减少不必要的CAS操作。

  • 轻量级锁状态:当有多个线程尝试获取同一个锁但竞争不激烈时,JVM会使用CAS操作来避免重量级锁带来的开销。

  • 重量级锁状态:在高竞争情况下,锁会膨胀为重量级锁,涉及操作系统级别的线程挂起和恢复,带来较高的性能开销。

synchronized的使用方式有:

1. synchronized 修饰实例方法(非静态方法)

当一个实例方法被声明为synchronized时,它会锁定调用该方法的对象(即当前对象,this)。这意味着同一时间只能有一个线程执行这个实例方法。

public class SynchronizedExample {public synchronized void synchronizedInstanceMethod() {// 同步代码块System.out.println(Thread.currentThread().getName() + " is executing synchronized instance method.");try {Thread.sleep(1000); // 模拟工作负载} catch (InterruptedException e) {e.printStackTrace();}}
}

2. synchronized 修饰静态方法

与同步实例方法类似,但同步静态方法锁定的是类的Class对象,而不是某个特定的对象实例。这意味着对于整个类的所有实例,同一时间只能有一个线程执行该静态同步方法。

public class SynchronizedExample {public static synchronized void synchronizedStaticMethod() {// 同步代码块System.out.println(Thread.currentThread().getName() + " is executing synchronized static method.");try {Thread.sleep(1000); // 模拟工作负载} catch (InterruptedException e) {e.printStackTrace();}}
}

synchronizedStaticMethod方法是静态同步的,所以无论哪个实例调用了这个方法,都会锁定该类的Class对象。

3. synchronized 修饰代码块

有时你可能不想同步整个方法,而是只同步其中的一部分代码。这时可以使用同步代码块,它可以指定要锁定的对象。

public class SynchronizedExample {private final Object lock = new Object();public void someMethod() {synchronized(lock) {// 需要同步的代码块System.out.println(Thread.currentThread().getName() + " is executing synchronized block.");try {Thread.sleep(1000); // 模拟工作负载} catch (InterruptedException e) {e.printStackTrace();}}}
}

在这个例子中,我们定义了一个私有的lock对象,并在需要同步的代码块周围使用了synchronized(lock)。这种方式允许更细粒度地控制哪些代码需要同步,同时减少了不必要的同步开销。


二、Java对象结构

学习Java对象结构时,需要有 JVM的相关知识作为背景。

Java对象(Object实例)结构包括三部分:对象头对象体对齐字节

1. 对象头

对象头包括三个字段:
  • Mark Word(标记字):用于存储自身运行时的数据例,如GC标志位、哈希码、锁状态等信息。
  • Class Pointer(类对象指针):用于存放此对象的元数据(InstanceKlass)的地址。虚拟机通过此指针可以确定这个对象是哪个类的实例。
  • Array Length(数组长度):如果对象是一个Java数组,那么此字段必须有,用于记录数组长度的数据;如果对象不是一个Java数组,那么此字段不存在,所以这是一个可选字段。
    在这里插入图片描述

2. 对象体

对象体包含了对象的实例变量(成员变量),用于成员属性值,包括父类的成员属性值。这部分内存按4字节对齐。

3. 对齐字节

对齐字节也叫作填充对齐,其作用是用来保证Java对象在所占内存字节数为8的倍数(8N bytes)。

并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。当对象实例数据部分没有对齐(8字节的整数倍)时,就需要通过对齐填充来补全。

HotSpot VM的内存管理要求对象起始地址必须是8字节的整数倍。对象头本身是8的倍数,当对象的实例变量数据不是8的倍数,需要填充数据来保证8字节的对齐。

4. 对象头中的字段长度

Mark WordClass PointerArray Length字段的长度都为JVM的一个Word(字)大小。

在32位JVM虚拟机中,字段长度都是是32位的;在64位JVM虚拟机中,字段长度都是64位的。

对于对象指针而言,如果JVM中对象数量过多,使用64位的指针将浪费大量内存。通过简单统计,64位的JVM将会比32位的JVM多耗费50%的内存。

为了节约内存可以使用选项+UseCompressedOops开启指针压缩。选项UseCompressedOops中的Oop部分为Ordinary object pointer(普通对象指针)的缩写。

如果开启UseCompressedOops选项,以下类型的指针将从64位压缩至32位:

  • Class对象的属性指针(即静态变量)。
  • Object对象的属性指针(即成员变量)。
  • 普通对象数组的元素指针。

当然,也不是所有的指针都会压缩,一些特殊类型的指针不会压缩,比如指向PermGen(永久代)的Class对象指针(JDK 8中指向元空间的Class对象指针)、本地变量、堆栈元素、入参、返回值和NULL指针等。

Mark Word的位长度不会受到OOP对象指针压缩选项的影响。

在堆内存小于32GB的情况下,64位虚拟机的UseCompressedOops选项是默认开启的,该选项表示开启Oop对象的指针压缩,会将原来64位的Oop对象指针压缩为32位。

  • 手动开启Oop对象指针压缩的Java指令为:java -XX:+UseCompressedOops mainclass
  • 手动关闭Oop对象指针压缩的Java指令为:java -XX:-UseCompressedOops mainclass

5. Mark Word 的结构信息

Java内置锁的涉及很多重要信息,这些都存放在对象结构中,并且存放于对象头的Mark Word字段中。Mark Word的位长度为JVM的一个Word大小,也就是说32位JVM的Mark Word为32位,4位JVM的Mark Word为64位。

Java内置锁的状态总共有4种,级别由低到高依次为:无锁偏向锁轻量级锁重量级锁

其实在JDK 1.6之前,Java内置锁还是一个重量级锁,是一个效率比较低下的锁。

在JDK 1.6之后,JVM为了提高锁的获取与释放效率,对synchronized的实现进行了优化,引入了偏向锁、轻量级锁的实现,从此以后Java内置锁的状态就有了4种(无锁偏向锁轻量级锁重量级锁),并且这4种状态会随着竞争的情况逐渐升级,而且是不可逆的过程,即不可降级,也就是说只能进行锁升级(从低级别到高级别)。

1. 不同锁状态下的 Mark Word 字段结构

Mark Word字段的结构与Java内置锁的状态强相关。为了让Mark Word字段存储更多的信息,JVM将Mark Word的最低两个位设置为Java内置锁状态位,不同锁状态下的32位Mark Word结构:

在这里插入图片描述

64位的Mark Word与32位的Mark Word结构相似:

在这里插入图片描述

2. 64 位 Mark Word 的构成

由于目前主流的JVM都是64位,使用64位的Mark Word,接下来对64位的Mark Word中各部分的内容做具体介绍。

  • lock:锁状态标记位,占两个二进制位,由于希望用尽可能少的二进制位表示尽可能多的信息,所以设置了lock标记。该标记的值不同,整个Mark Word表示的含义不同。
  • biased_lock:对象是否启用偏向锁标记,只占1个二进制位。为1时表示对象启用偏向锁,为0时表示对象没有偏向锁。

lockbiased_lock两个标记位组合在一起,共同表示 Object实例处于什么样的锁状态。二者组合的含义如下:
在这里插入图片描述

  • age:4位的Java对象分代年龄。在GC中,如果对象在Survivor区复制一次,年龄增加1。当对象达到设定的阈值时,将会晋升到老年代。默认情况下,并行GC的年龄阈值为15,并发GC的年龄阈值为6。由于age只有4位,因此最大值为15,这就是-XX:MaxTenuringThreshold选项最大值为15的原因。

  • identity_hashcode:31位的对象标识HashCode(哈希码)采用延迟加载技术,当调用Object.hashCode()方法或者System.identityHashCode()方法计算对象的HashCode后,其结果将被写到该对象头中。当对象被锁定时,该值会移动到Monitor(监视器)中。

  • thread:54位的线程ID值为持有偏向锁的线程ID。

  • epoch:偏向时间戳。

  • ptr_to_lock_record:占62位,在轻量级锁的状态下指向栈帧中锁记录的指针。

  • ptr_to_heavyweight_monitor:占62位,在重量级锁的状态下,指向对象监视器的指针。

32位的Mark Word与64位Mark Word结构相似,这里不再赘述。

6. 使用 JOL 工具查看对象的布局


三、Java 内置锁机制

3.1 内置锁的演进过程

在JDK 1.6版本之前,所有的Java内置锁都是重量级锁。重量级锁会造成CPU在用户态和核心态之间频繁切换,所以代价高、效率低。

JDK 1.6版本为了减少获得锁和释放锁所带来的性能消耗,引入了“偏向锁”和“轻量级锁”实现。所以,在JDK 1.6版本里内置锁一共有4种状态:无锁状态偏向锁状态轻量级锁状态重量级锁状态,这些状态随着竞争情况逐渐升级。内置锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种能升级却不能降级的策略,其目的是为了提高获得锁和释放锁的效率。

1. 无锁状态

当一个对象刚刚创建时,它处于无锁状态(也称为自由状态)。这意味着没有任何线程试图获取该对象的锁,因此可以认为它是自由访问的。偏向锁标识位是0、锁状态01。无锁状态下对象的Mark Word如下:
在这里插入图片描述

2. 偏向锁状态

偏向锁是JVM的一种优化技术,主要针对锁只会被单个线程持有的场景。它的核心思想是假设锁总是由同一个线程获得,从而避免每次进入同步块时都进行昂贵的原子操作(如CAS操作)。
【重点】

  • “偏向”:指的是内置锁会偏向于当前已经占有过自己的线程。
  • 无锁转变为偏向锁的过程:
    1. 无锁转向偏向锁 :当线程A第一次尝试获取内置锁时,如果此时对象处于无锁状态,并且没有其他线程竞争该锁,则JVM会将该对象的锁状态从无锁转变为偏向锁。在转变为偏向锁的过程中,JVM会在对象头中标记该锁为偏向锁,并记录下持有该锁的线程ID。
    2. 尝试获取偏向锁线程A再次尝试获取该内置锁时,可以直接进入,无需执行任何同步操作,因为系统“偏向”了这个线程。
    3. 撤销偏向锁:在线程 A第二次获取内置锁之前,线程 B 尝试获取该内置锁,那么当前的偏向锁会被撤销,转而升级为轻量级锁或者根据竞争情况进一步升级为重量级锁。
  • 原理:如果不存在线程竞争的一个线程获得了锁,那么锁就进入偏向状态,此时Mark Word的结构变为偏向锁结构,锁对象的锁标志位(lock)被改为01,偏向标志位(biased_lock)被改为1,然后线程的ID记录在锁对象的Mark Word中(使用CAS操作完成)。以后该线程获取锁的时候判断一下线程ID和标志位,就可以直接进入同步块,连CAS操作都不需要,这样就省去了大量有关锁申请的操作,从而也就提升了程序的性能。

偏向锁状态下对象的Mark Word具体如下:
在这里插入图片描述

3. 轻量级锁状态

  • 当锁处于偏向锁状态,但是锁又被另一个线程所企图抢占时,偏向锁就会升级为轻量级锁。企图抢占的线程会通过自旋的形式尝试获取锁,不会阻塞抢锁线程,以便提高性能。
  • 两个线程公平竞争,哪个线程先占有锁对象,锁对象的Mark Word就指向哪个线程的栈帧中的锁记录。

轻量级锁状态下对象的Mark Word如图所示:
在这里插入图片描述

自旋的基本思想是让一个线程不断地检查某个条件是否满足,而不是直接进入阻塞状态。

如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要不断地检查某个条件是否满足,等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核切换的消耗。

但是,线程自旋是需要消耗 CPU的,如果一直获取不到锁,则线程也不能一直占用CPU自旋做无用功,所以需要设定一个自旋等待的最大时间。

轻量级锁主要有两种:普通自旋锁自适应自旋锁

普通自旋锁

所谓普通自旋锁,就是指当有线程来竞争锁时,抢锁线程会在原地循环等待,而不是被阻塞,直到那个占有锁的线程释放锁之后,这个抢锁线程才可以获得锁。

默认情况下,自旋的次数为10次,用户可以通过-XX:PreBlockSpin选项来进行更改。

自适应自旋锁

所谓自适应自旋锁,就是等待线程空循环的自旋次数并非是固定的,而是会动态地根据实际情况来改变自旋等待的次数,自旋次数由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。

自适应自旋锁的大概原理是:

  • 如果抢锁线程在同一个锁对象上之前成功获得过锁,那么JVM就会认为这次自旋也很有可能再次成功,因此允许自旋等待持续相对更长的时间。

  • 如果对于某个锁,抢锁线程在很少成功获得过,那么JVM将可能减少自旋时间甚至省略自旋过程,以避免浪费处理器资源。

自适应自旋解决的是“锁竞争时间不确定”的问题。自适应自旋假定不同线程持有同一个锁对象的时间基本相当,竞争程度趋于稳定。总的思想是:根据上一次自旋的时间与结果调整下一次自旋的时间。

JDK 1.6的轻量级锁使用的是普通自旋锁,且需要使用-XX:+UseSpinning选项手工开启。

JDK 1.7后,轻量级锁使用自适应自旋锁,JVM启动时自动开启,且自旋时间由JVM自动控制。

4. 重量级锁状态

重量级锁会让其他申请的线程之间进入阻塞,性能降低。重量级锁也就叫同步锁,这个锁对象Mark Word再次发生变化,会指向一个监视器对象,该监视器对象用集合的形式来登记和管理排队的线程。重量级锁状态下对象的Mark Word具体

在JVM中,每个对象都关联一个监视器,这里的对象包含了Object实例和Class实例。监视器是一个同步工具,相当于一个许可证,拿到许可证的线程即可以进入临界区进行操作,没有拿到则需要阻塞等待。重量级锁通过监视器的方式保障了任何时间只允许一个线程通过受到监视器保护的临界区代码。

核心原理

JVM中每个对象都会有一个监视器,监视器和对象一起创建、销毁。监视器相当于一个用来监视这些线程进入的特殊房间,其义务是保证(同一时间)只有一个线程可以访问被保护的临界区代码块。

本质上,监视器是一种同步工具,也可以说是一种同步机制,主要特点是:

  • 同步。监视器所保护的临界区代码是互斥地执行的。一个监视器是一个运行许可,任一个线程进入临界区代码都需要获得这个许可,离开时把许可归还。

  • 协作。监视器提供Signal机制,允许正持有许可的线程暂时放弃许可进入阻塞等待状态,等待其他线程发送Signal去唤醒;其他拥有许可的线程可以发送Signal,唤醒正在阻塞等待的线程,让它可以重新获得许可并启动执行。

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

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

相关文章

LLM(3): Transformer 架构

Transformer 架构是当前大语言模型的主力架构和基础技术,本文以通俗易懂的方式,对此作简要介绍。 1.4 介绍 Transformer 架构 大多数现代的大规模语言模型(LLMs)依赖于 Transformer 架构,这是一种在 2017 年的论文《…

88.HarmonyOS NEXT 性能监控与调试指南:构建高性能应用

温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦! HarmonyOS NEXT 性能监控与调试指南:构建高性能应用 文章目录 HarmonyOS NEXT 性能监控与调试指南:构建高性能应用1. 性能监…

012---状态机的基本知识

1. 摘要 文章为学习记录。主要介绍状态机概述、状态转移图、状态编码、状态机写法、状态机代码示例。 2. 状态机概述 状态机 (Finite State Machine),也称为同步有限状态机,用于描述有先后顺序或时序规律的事情。 “同步”&…

deepseek+kimi做ppt教程记录

1.首先注册deepseek和kimi deepseek官网:https://chat.deepseek.com/ kimi官网:https://kimi.moonshot.cn/ 以下以一篇工作总结报告为例 2.使用deepseek生成ppt大纲 让deepseek生成kimi生成ppt所需要的内容时,需要注意提示词内容,…

【Linux内核系列】:文件系统收尾以及软硬链接详解

🔥 本文专栏:Linux 🌸作者主页:努力努力再努力wz 💪 今日博客励志语录: 世界上只有一种个人英雄主义,那么就是面对生活的种种失败却依然热爱着生活 内容回顾 那么在之前的学习中,我们…

最新版Chrome浏览器加载ActiveX控件技术--allWebPlugin中间件一键部署浏览器扩展

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品,致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX控件直接嵌入浏览器,实现插件加载、界面显示、接口调用、事件回调等。支持Chrome、Firefo…

基于SpringBoot和MybatisPlus实现通用Controller

基于SpringBoot和MybatisPlus实现通用Controller,只需要创建实体类和mapper接口,单表增删改查接口就已经实现,提升开发效率 1.定义通用controller package com.xian.controller;import cn.hutool.core.map.MapUtil; import com.baomidou.my…

Axure大屏可视化原型模板及素材:数据可视化的高效解决方案

数据可视化已成为企业决策、运营分析、市场洞察的重要工具。数据可视化大屏,作为数据展示和交互的直观平台,能够实时呈现关键数据,帮助企业快速做出决策。Axure作为原型设计领域的领先工具,以其丰富的组件库、强大的交互设计能力和…

YOLOE:实时查看任何事物

摘要 https://arxiv.org/pdf/2503.07465v1 目标检测和分割在计算机视觉应用中得到了广泛应用,然而,尽管YOLO系列等传统模型高效且准确,但它们受限于预定义的类别,阻碍了在开放场景中的适应性。最近的开放集方法利用文本提示、视觉…

這是我第一次寫關於aapenal服務器管理控制面板的文章

首先我們來認識一下服務器管理面板的所有功能  網站管理功能: 支持創建和管理多個網站。配置虛擬主機(Vhost)和域名綁定。自動安裝常用應用(如WordPress、Joomla等)。  文件管理功能: 文件上傳、…

jmeter:登录接口的token用于下一个接口

问题: 仅仅登录接口可以使用,其他接口进行测试的时候都是报错:账号已经失效 原因: 应该是登录接口的token并没有用到下一个接口上来 解决方法 1、目录建设如下: 2、先添加一个后置处理器:查看结果数&…

1、操作系统引论

一、操作系统 会使用linux系统 建议大家先学会linux的基础指令,可以看菜鸟教程网站进行学习。 1、各种定义 操作系统定义 管理计算机的 硬件 和软件资源, 能对各类作业进行调度,方便用户使用计算机的程序集合。操作系统运行在内核态&#xf…

SpringCloud系列教程(十四):Sentinel持久化

Sentinel之前已经搭建和应用成功了,但是它有一个很大的缺点就是官方没有提供持久化的方案,从项目源码上看感觉这款工具也没有完成的太好,所以需要我们去对它进行二次开发。要补充的功能大概如下: 1、将Sentinel接入nacos中&#…

Go语言环境搭建并执行第一个Go程序

目录 一、Windows环境搭建 二、vscode安装插件 三、运行第一个go程序 一、Windows环境搭建 下载Go:All releases - The Go Programming Language 这里是Windows搭建,选择的是windows-amd64.msi,也可以选择zip直接解压缩到指定目录 选择msi…

Java数据结构第二十三期:Map与Set的高效应用之道(二)

专栏:Java数据结构秘籍 个人主页:手握风云 目录 一、哈希表 1.1. 概念 1.2. 冲突 1.3. 避免冲突 1.4. 解决冲突 1.5. 实现 二、OJ练习 2.1. 只出现一次的数字 2.2. 随机链表的复制 2.3. 宝石与石头 一、哈希表 1.1. 概念 顺序结构以及平衡树中…

OpenHarmony子系统开发 - Rust编译构建指导

OpenHarmony子系统开发 - Rust编译构建指导 一、Rust模块配置规则和指导 概述 Rust是一门静态强类型语言,具有更安全的内存管理、更好的运行性能、原生支持多线程开发等优势。Rust官方也使用Cargo工具来专门为Rust代码创建工程和构建编译。 OpenHarmony为了集成C…

STM32驱动代码规范化编写指南(嵌入式C语言方向)

点击下面图片,为您提供全新的嵌入式学习路线 文章目录 一、命名规范体系1.1 变量/函数命名1.2 宏定义规范1.3 类型定义 二、代码结构组织2.1 文件组织结构2.2 头文件规范模板 三、注释体系构建3.1 Doxygen风格示例3.2 复杂逻辑注释 四、硬件抽象层设计4.1 寄存器封…

Trae与Builder模式初体验

说明 下载的国际版:https://www.trae.ai/ 建议 要选新模型 效果 还是挺不错的,遇到问题反馈一下,AI就帮忙解决了,真是动动嘴(打打字就行了),做些小的原型效果或演示Demo很方便呀&#xff…

【设计模式】《设计模式:可复用面向对象软件的基础》:设计模式怎样解决设计问题?

文章目录 ⭐前言⭐一、设计模式怎样解决设计问题?🌟1、寻找合适的对象🌟2、决定对象的粒度🌟3、指定对象接口🌟4、描述对象的实现🌟5、运用复用机制✨(1)针对接口编程,而不是针对实现编程。✨(2…

【项目管理git】git学习

ps:所有东西都是个人理解 文章目录 一、git是什么,它用来做什么?二、相关知识库2.1 简单的linux指令2.2 git配置指令2.3 git常见的指令2.3.1 Git的上传原理2.3.2 版本回退相关内容 2.4 设置远程地址,本地上传到github2.4.1 ssh相…