网站优化简历模板网站开发公司多少钱
web/
2025/10/6 13:30:25/
文章来源:
网站优化简历模板,网站开发公司多少钱,汉中专业网站建设价格,天元建设集团有限公司六大板块目录 以下知识基于HotSpot虚拟机实现
1.前置知识
1.1 锁的作用
1.2 Java中常见的锁类型
1.3 锁的重入
2.使用场景
2.1 修饰实例方法
2.1.1 用法
2.1.2 原理
2.1.3 特点
2.2 修饰静态方法
2.2.1 用法
2.2.2 原理
2.3 修饰代码块
2.3.1 用法
3.原理
3.1 对象锁
…目录 以下知识基于HotSpot虚拟机实现
1.前置知识
1.1 锁的作用
1.2 Java中常见的锁类型
1.3 锁的重入
2.使用场景
2.1 修饰实例方法
2.1.1 用法
2.1.2 原理
2.1.3 特点
2.2 修饰静态方法
2.2.1 用法
2.2.2 原理
2.3 修饰代码块
2.3.1 用法
3.原理
3.1 对象锁
3.1.1 对象锁的实现原理
3.1.1.1 无锁
3.1.1.2 偏向锁
3.1.1.3 轻量级锁
3.1.1.4 重量级锁
3.1.1.2.1 Monitor
3.1.2 锁升级
3.1.3 锁消除
3.1.4 锁粗化
3.2 对象头
3.2.1 对象头的结构
3.2.1.1 MarkWord
PS这里分代年龄是4位bit也说明了为什么分代年龄最大是15。
3.2.1.1 指向类的指针class pointer 以下知识基于HotSpot虚拟机实现
1.前置知识
1.1 锁的作用
锁是一种同步机制,可以用来协调多个线程的并发访问,以保证对共享资源的安全访问。可以理解为防止一件东西同时被多个人使用。
1.2 Java中常见的锁类型
Java中常见的锁类型-CSDN博客
1.3 锁的重入
锁的重入是指在一个线程持有锁的情况下可以重复获取同一个锁而不会发生死锁。正常来说a获取到锁后b不能获取锁但是当一个实例内的a方法和b方法都是用一把锁上锁时同一个线程访问a和b就需要重入的能力比如在a方法中访问b方法那么a的锁x已经被抢占了如果不支持重入那么访问b的时候会发现x锁已经被自己抢占而无法访问支持重入的原理也就是在这里判断一下当前方法的锁是否是本线程拥有的锁。
2.使用场景
2.1 修饰实例方法
2.1.1 用法
public class SynchronizedExample {// 使用synchronized修饰的实例方法public synchronized void increment() {}
}
2.1.2 原理
Java通过锁住此方法对应的对象锁实现同步访问。具体查看3.1
2.1.3 特点 由于锁定的是对象锁那么会有一下特点 1.同一个实例对象下被Synchronized修饰的方法会互相影响也就是说当访问同一个实例对象中被Synchronized修饰的a方法时其他线程无法访问这个实例对象下被被Synchronized修饰的b方法。 2.被Synchronized修饰的方法与未被Synchronized修饰的方法互不影响 3.但是如果是同一线程访问a方法后和b方法不会被阻塞因为Synchronized支持重入查看1.3 2.2 修饰静态方法
2.2.1 用法
synchronized void staic method() {
}
2.2.2 原理
Java通过锁住此方法对应的类的对象锁实现同步访问。具体查看3.1
静态同步方法, 锁是当前类的Class对象。一个类只有一个类对象类对象的锁也是和3.1中对象锁原理一样
2.3 修饰代码块
2.3.1 用法
synchronized(this) {
}
锁是synchronized括号里实例的对象。
synchronized(a.class) {
}
锁是synchronized括号里类的class对象。
3.原理
这里需要一些前置知识每一个对象可以关联一个ObjectMonitor对象对象中有个对象头的区域Java在不同场景下通过利用对象头以及ObjectMonitor对象来实现对象锁。
3.1 对象锁
JVM在JDK1.6后会有几种状态线程获取对象时分别会判断对象锁的状态以此来决定线程是否进入阻塞或者获取到锁对象执行代码块或者自旋等接下来的动作。
对象锁是Java中用于实现同步的机制之一它可以确保在多线程环境下对共享资源的访问是安全的。对象锁的重量级锁状态是基于对象的监视器monitor实现的在Java中每个对象都有一个与之关联的监视器用于实现同步。
3.1.1 对象锁的实现原理 最开始JDK1.5以及以前java只有重量级锁。 从JDK1.6开始对象锁有4种状态无锁偏向锁轻量级锁重量级锁。 这四种状态由3.2.1.1 中的MarkWord内的是否偏向锁或锁标志位确定。 先了解四种状态的特点
3.1.1.1 无锁
当MarkWord的是否偏向锁位为0锁标志位为01时。对象锁为无锁状态
3.1.1.2 偏向锁
当MarkWord的是否偏向锁位为1锁标志位为01时。对象锁为偏向锁状态 当偏向锁开启状态时一个线程需要获取对象锁时需要将Markword的偏向线程id位修改为自己的线程id。修改方式为CAS操作。当有其他线程访问此对象锁时偏向锁升级为轻量级锁。 偏向锁的释放 偏向锁只有遇到其他线程尝试竞争偏向锁时持有偏向锁的线程才会释放锁线程不会主动去释放偏向锁。偏向锁释放后就会升级为轻量级锁。 3.1.1.3 轻量级锁
当MarkWord的锁标志位为01时。对象锁为轻量级状态 线程在执行同步块之前JVM会先在当前线程的栈桢中创建用于存储锁记录的空间并将对象头中的Mark Word复制到锁记录中官方称为Displaced Mark Word。然后线程尝试使用 CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功当前线程获得锁如果失败表示其他线程竞争锁当前线程便尝试使用自旋来获取锁如果自旋一定次数默认为10可以通过参数-XX:PreBlockSpin来调整。--XX:UseSpinning参数来开启自旋JDK1.6之前默认关闭自旋后依旧获取不到锁轻量级锁会膨胀为重量级锁且当前自旋的线程会阻塞。很多博客对这里说得含糊不清需要注意。 轻量级锁中某进程cas失败后自旋的意义是为了减少线程从用户态到内核态的上下文切换。CPU对这两种状态的切换比较耗时
补充 自适应自旋锁 JDK 1.6引入了更加聪明的自旋锁即自适应自旋锁。所谓自适应就意味着自旋的次数不再是固定的它是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。 3.1.1.4 重量级锁
当MarkWord的锁标志位为10时。对象锁为重量级状态对象锁进入重量级状态后将采用monitor的方式加锁和释放锁。
3.1.1.4.1 Monitor
对象锁在重量级状态时是通过进入、退出 对象监视器(Monitor) 来实现对方法、代码块的同步的而对象监视器的本质依赖于底层操作系统的 互斥锁(Mutex Lock) 实现。 互斥锁(Mutex Lock) 一种常见的线程同步机制用于保护共享资源在多线程环境下的互斥访问。它提供了两个基本操作加锁Lock和解锁Unlock。 互斥锁的原理和实现方式可以有多种常见的实现包括使用原子操作、互斥变量、硬件指令等。下面是一个常见的互斥锁实现原理的简要分析 原子操作实现原子操作是一种不可中断的操作能够保证在多线程环境下的原子性。互斥锁的实现中常用的原子操作是比较并交换Compare and SwapCAS操作。具体实现中互斥锁内部维护一个标志位用于表示锁的状态。加锁操作通过原子的CAS操作将标志位从未锁定状态修改为锁定状态如果修改成功则表示获取锁成功否则需要重试。解锁操作将标志位恢复为未锁定状态。 互斥变量实现互斥变量是一种特殊的变量它具有原子性操作和线程同步的特性。互斥锁的实现中互斥变量被用作一个标志位用于表示锁的状态。加锁操作通过原子的测试和设置操作来获取互斥变量的值如果互斥变量的值为未锁定状态则将其设置为锁定状态表示获取锁成功。解锁操作将互斥变量的值恢复为未锁定状态。 硬件指令实现一些处理器架构提供了特定的硬件指令来支持互斥锁的实现。这些指令通常能够在单个指令级别上执行锁的加锁和解锁操作具有较高的性能和效率。这些硬件指令可以保证锁的操作是原子的从而实现线程的同步和互斥访问。 代码块的加锁 字节码的入口和出口分别有monitorenter和monitorexit指令。当执行monitorenter指令时线程试图获取锁也就是获取monitormonitor对象存在于每个Java对象的对象头中synchronized锁便是通过这种方式获取锁的也是为什么Java中任意对象可以作为锁的原因的持有权。当计数器为0则可以成功获取获取后将锁计数器设为1也就是加1。相应的在执行monitorexit指令后将锁计数器设为0表明锁被释放。如果获取对象锁失败那当前线程就要阻塞等待直到锁被另外一个线程释放为止。大部分博客都是如是说但是这里不准确对象头中存放的是指向重量级锁的指针也就是之前提到的每一个对象可以关联的那个ObjectMonitor对象。 方法的加锁 字节码中是添加ACC_SYNCHRONIZED标识该标识指明了该方法是一个同步方法JVM通过该ACC_SYNCHRONIZED访问标志来辨别一个方法是否声明为同步方法从而执行相应的同步调用。 虽然字节码的标识不一样但是都是会获取Monitor对象去做操作。
monitor的结构 刚开始 Monitor 中 Owner 为 null 当 Thread-2 执行 synchronized(obj) 就会将Monitor的所有者 Owner 置为Thread-2 Monitor中只能有一个Owner 在Thread-2上锁的过程中如果Thread-3Thread-4Thread-5也来执行synchronized(obj)就会进入EntryList BLOCKED Thread-2执行完同步代码块中的内容然后唤醒EntryList中等待的线程来竞争锁竞争时是非公平的 图中WaitSet中的Thread-0Thread-1是之前获得过锁但条件不满足进入WAITING状态的线程在wait-notify中 3.1.2 锁升级
锁升级是在线程获取对象锁时对象锁状态的一种切换。对象锁的状态也实时影响着获取对象锁的线程的状态是否阻塞等。 手动开启或关闭偏向锁你可以使用 -XX:UseBiasedLocking 或 -XX:-UseBiasedLocking 参数来控制。 需要注意的 开启偏向锁的时候对象锁只有 偏向锁-轻量级锁-重量级锁的升级流程。 关闭偏向锁的时候对象锁只有 无锁-轻量级锁-重量级锁的升级流程。 3.1.3 锁消除
为了保证数据的完整性我们在进行操作时需要对这部分操作进行同步控制但是在有些情况下JVM检测到不可能存在共享数据竞争这是JVM会对这些同步锁进行锁消除。锁消除的依据是逃逸分析的数据支持。 如果不存在竞争为什么还需要加锁呢 所以锁消除可以节省毫无意义的请求锁的时间。变量是否逃逸对于虚拟机来说需要使用数据流分析来确定但是对于我们程序员来说这还不清楚么我们会在明明知道不存在数据竞争的代码块前加上同步吗但是有时候程序并不是我们所想的那样 我们虽然没有显示使用锁但是我们在使用一些JDK的内置API时如StringBuffer、Vector、HashTable等这个时候会存在隐形的加锁操作。 逃逸分析
Java - 深入理解Java中的逃逸分析_java doescapeanalysis-CSDN博客
3.1.4 锁粗化
就是将多个连续的加锁、解锁操作连接在一起扩展成一个范围更大的锁。
3.2 对象头
对象有三块区域对象头Header、实例数据Instance Data和对齐填充Padding。
3.2.1 对象头的结构
对象头由三部分组成MarkWord指向类的指针数组长度只有数组对象才有
3.2.1.1 MarkWord
Mark Word记录了对象和锁有关的信息当这个对象被synchronized关键字当成同步锁时围绕这个锁的一系列操作都和Mark Word有关。
Mark Word在32位JVM中的长度是32bit在64位JVM中长度是64bit。
Mark Word在不同的锁状态下存储的内容不同在32位JVM中是这么存的 Mark Word在不同的锁状态下存储的内容不同在64位JVM中是这么存的 PS这里分代年龄是4位bit也说明了为什么分代年龄最大是15。
3.2.1.1 指向类的指针class pointer
在看此部分时候需要提前了解类实例对象类的class对象的区别是三个东西。
即指向方法区的instanceKlass实例 虚拟机通过这个指针来确定这个对象是哪个类的实例。 上图是JDK1.6的状态。
1.7和1.8中class的实例对象是放在堆中了
具体可查看这篇博客类的class实例对象存放位置
https://www.cnblogs.com/xy-nb/p/6773051.html 参考博客
Java的对象头和对象组成详解_hotspot虚拟机中java对象结构的图示-CSDN博客
https://www.cnblogs.com/thiaoqueen/p/9314745.html
开启偏向锁一定性能更好吗_jvm偏向锁导致性能问题-CSDN博客
Java - 深入理解Java中的逃逸分析_java doescapeanalysis-CSDN博客
Synchronized 关键字原理-CSDN博客
synchronized详解-CSDN博客
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/87933.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!