当前位置: 首页 > news >正文

常州建设网站公司网站门户网站的类型

常州建设网站公司网站,门户网站的类型,头条网站怎么做,12306建网站多少钱目录 JVM内置锁synchronized关键字详解 设计同步器的意义 如何解决线程并发安全问题#xff1f; synchronized原理详解 synchronized底层原理 synchronized在jdk1.6前后的变化【重点】 jdk小于1.6时 jdk1.6时 轻量级锁何时升级为重量级锁#xff1f;#xff1f;…目录 JVM内置锁synchronized关键字详解 设计同步器的意义 如何解决线程并发安全问题 synchronized原理详解 synchronized底层原理 synchronized在jdk1.6前后的变化【重点】 jdk小于1.6时 jdk1.6时 轻量级锁何时升级为重量级锁 锁膨胀是可逆的吗 ReentrantLock Monitor监视器锁 什么是monitor 对象的内存布局 对象头 对象头分析工具 System.out.println()方法的坑 锁的膨胀升级过程【synchronized优化的思路】【重点】 偏向锁 轻量级锁 自旋 锁消除 锁粗化 分析重量级锁和轻量级的总结为什么加重量级锁(挂起阻塞线程)时消耗性能大 逃逸分析 代码 测试分析 原理分析 总结 但是逃逸分析存在缺点 锁膨胀举例【了解即可】 举例1 JVM内置锁synchronized关键字详解 设计同步器的意义 多线程编程中有可能会出现多个线程同时进行访问同一个共享可变的资源的情况这个资源我们称之为临界资源这种资源可能是对象变量文件等。 共享资源可以由多个线程同时访问 可变资源可以在其生命周期内被修改 引出的问题 由于线程执行的过程是不可控的所以需要采用同步机制来协同对对象可变状态的访问 如何解决线程并发安全问题 实际上所有的并发模式在解决线程安全问题时采用的方案都是序列化访问临界资源。即在同一时刻只能有一个线程访问临界资源也称作同步互斥访问。 Java 中提供了两种方式来实现同步互斥访问synchronized 和 Lock 同步器的本质就是加锁 加锁的目的序列化访问临界资源即同一时刻只能有一个线程访问临界资源(同步互斥访问) 不过有一点需要区别的是当多个线程执行一个方法时该方法内部的局部变量并不是临界资源因为这些局部变量是在每个线程的私有栈中的因此不具有共享性不会导致线程安全问题。 synchronized原理详解 synchronized(JVM内置锁)是一种对象锁(锁的是对象而非引用)作用粒度是对象可以用来实现对临界资源的同步互斥访问是可重入的。 加锁的方式 1.同步实例方法锁是当前实例对象 2.同步类方法锁是当前类对象 3.同步代码块锁是括号里面的对象 synchronized底层原理 synchronized是基于JVM内置锁实现的通过内部对象Monitor(监视器锁)实现基于进入与退出Monitor对象实现方法与代码块同步监视器锁的实现依赖底层操作系统的Mutex lock互斥锁实现它是一个重量级锁性能较低。当然JVM内置锁在1.5之后版本做了重大的优化如锁粗化Lock Coarsening、锁消除Lock Elimination、轻量级锁Lightweight Locking、偏向锁Biased Locking、适应性自旋Adaptive Spinning等技术来减少锁操作的开销内置锁的并发性能已经基本与Lock持平。 synchronized关键字被编译成字节码后会被翻译成monitorenter 和 monitorexit 两条指令分别在同步块逻辑代码的起始位置与结束位置。 如图演示 每个同步对象都有一个自己的Monitor(监视器锁)加锁过程如下图所示 synchronized在jdk1.6前后的变化【重点】 jdk小于1.6时 synchronized的性能十分的低因为底层是由操作系统去维护的。 操作系统的内存空间分为用户空间和内核空间内存空间分为两类内核线程模型和用户线程模型。对于Java程序来说它是属于内核线程模型。 内核线程模型的线程表是存在于内核空间的[线程表存储着CPU与JVM线程栈一一调度的映射关系与其说是CPU调度Java栈的线程不如说是操作系统底层的线程表进行调度Java线程栈的线程]。由于一开始是处于用户空间的所以操作时需要从用户态切换到内核态(即是从用户空间切换到内核空间)。 我们知道切换的效率是很低的大量消耗性能。所以在jdk1.6之前synchronized底层由操作系统维护是性能极低的。 jdk1.6时 synchronized进行优化分析过程 (1) 当只有一个线程获取锁时此时是不存在锁竞争的所以无需加重量级锁一棒子打死而是进行加一个偏向锁。 (2)当多个线程进入竞争获取锁时此时也不会立马让synchronized分配一个重量级锁而是先分配一个轻量级锁。 一个线程先获取到该锁对象 然后进行执行代码块中的任务逻辑。其它线程也会进入synchronized内部但是会类似给其它线程一个while循环 让其它没有获取到锁对象的线程进行循环等待【spin自旋】。当获取到轻量级锁的线程执行完任务逻辑后会进行释放锁其它线程停止循环等待然后去竞争这把锁线程无需阻塞也无需线程上下文的切换。 (3) 但是如果获取到锁的线程执行代码块中业务逻辑时间过长或者锁竞争太激烈了(线程过多单一线程获取锁的概率降低)导致其它线程循环等待的次数大于synchronized内部规定的数值时此时就会发生锁膨胀升级轻量级锁为重量级锁。此时其它没 有获取到锁的线程就不再循环等待了【spin自旋】而是变为阻塞等待。这样性能就会极具下降 轻量级锁何时升级为重量级锁 其实就是对比两部分的性能消耗。 (1) 上轻量级锁,没有获取到锁的线程进行循环等待时所消耗CPU的性能 (2)上重量级锁没有获取到锁的线程会阻塞当锁释放后线程去唤醒阻塞的线程所消耗的性能完成操作系统底层空间的切换(用户空间切换到内核空间)所消耗的性能 如果(1)大于(2)那么轻量级锁升级为重量级锁。 如果(1)小于(2)那么使用轻量级锁。 锁膨胀是可逆的吗 不是。锁膨胀就是轻量级锁膨胀转化为重量级锁锁膨胀的原因就是线程竞争锁激烈或任务执行调度时间过长导致循环等待时间过长(等待时间过长则会导致CPU性能消耗过大)如果锁膨胀可逆那么肯定会有一天再次发生锁膨胀并且锁转化的过程也是极其消耗性能的。锁膨胀可逆的观点是错误的。 ReentrantLock 总结 ReentrantLock锁的性能和jdk1.6之后优化过的synchronized性能差不多。主要还是看怎么去使用。 Monitor监视器锁 任何一个对象都有一个Monitor与之关联当且一个Monitor被持有后它将处于锁定状态。Synchronized在JVM里的实现都是 基于进入和退出Monitor对象来实现方法同步和代码块同步虽然具体实现细节不一样但是都可以通过成对的MonitorEnter和MonitorExit指令来实现。 monitorenter每个对象都是一个监视器锁monitor。当monitor被占用时就会处于锁定状态线程执行monitorenter指令时尝试获取monitor的所有权过程如下如果monitor的进入数为0则该线程进入monitor然后将进入数设置为1该线程即为monitor的所有者如果线程已经占有该monitor只是重新进入则进入monitor的进入数加1如果其他线程已经占用了monitor则该线程进入阻塞状态直到monitor的进入数为0再重新尝试获取monitor的所有权 monitorexit执行monitorexit的线程必须是objectref所对应的monitor的所有者。指令执行时monitor的进入数减1如果减1后进入数为0那线程退出monitor不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个 monitor 的所有权当然退出monitor的线程也可以进行重新竞争该monitor的使用权。 monitorexit指令出现了两次第1次为同步正常退出释放锁第2次为发生异步退出释放锁monitorexit第二次退出释放锁是一个健壮性退出。 通过上面两段描述我们应该能很清除的看出Synchronized的实现原理Synchronized的语义底层是通过一个monitor的对象来完成的其实wait/notify等方法也依赖于monitor对象这就是为什么只有在同步的块或者方法中才能进行调用wait/notify等方法否则会抛出java.lang.IllegalMonitorStateException的异常的原因。 看一个同步方法 public class SynchronizedMethod {public synchronized void method() {System.out.println(Hello World!);} } 反编译结果 从编译的结果来看方法的同步并没有通过指令 monitorenter 和 monitorexit 来完成理论上其实也可以通过这两条指令来实现不过相对于普通方法其常量池中多了 ACC_SYNCHRONIZED 标示符。 JVM就是根据该标示符来实现方法的同步的 当方法调用时调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置如果设置了执行线程将先获取monitor获取成功之后才能执行方法体方法执行完后再释放monitor。在方法执行期间其他任何线程都无法再获得同一个monitor对象。 两种同步方式本质上没有区别只是方法的同步是一种隐式的方式来实现无需通过字节码来完成。两个指令的执行是JVM通过调用操作系统的互斥原语mutex来实现被阻塞的线程会被挂起、等待重新调度会导致“用户态和内核态”两个态之间来回切换对性能有较大影响。 什么是monitor 可以把它理解为 一个同步工具也可以描述为 一种同步机制它通常被 描述为一个对象。与一切皆对象一样所有的Java对象是天生的Monitor每一个Java对象都有成为Monitor的潜质因为在Java的设计中 每一个Java对象自打娘胎里出来就带了一把看不见的锁它叫做内部锁或者Monitor锁。也就是通常说Synchronized的对象锁MarkWord锁标识位为10其中指针指向的是Monitor对象的起始地址。在Java虚拟机HotSpot中Monitor是由ObjectMonitor实现的其主要数据结构如下位于HotSpot虚拟机源码ObjectMonitor.hpp文件C实现的 ObjectMonitor() {_header NULL;_count 0; // 记录个数_waiters 0,_recursions 0;_object NULL;_owner NULL;_WaitSet NULL; // 处于wait状态的线程会被加入到_WaitSet_WaitSetLock 0 ;_Responsible NULL ;_succ NULL ;_cxq NULL ;FreeNext NULL ;_EntryList NULL ; // 处于等待锁block状态的线程会被加入到该列表_SpinFreq 0 ;_SpinClock 0 ;OwnerIsThread 0 ;} ObjectMonitor中有两个队列_WaitSet和_EntryList用来进行保存ObjectWaiter对象列表(每个等待锁的线程都会被封装为ObjectWaiter对象)_owner指向持有ObjectMonitor对象的线程当多个线程同时访问一段同步代码时 1.首先会进入_EntryList集合当线程获取到对象的monitor后进入_Owner区域并且把monitor中的owner变量设置为当前线程同时把monitor中的计数器count 加 1 2.若线程调用wait()方法将释放当前持有的monitorowner恢复为nullcount自减1同时该线程进入WaitSet集合中等待被唤醒 3.若当前线程执行完毕也将释放monitor锁并复位count的值以便其他线程进入获取monitor(锁) 同时Monitor对象存在于每一个Java对象的对象头Mark Word中(存储的指针的指向)Synchronized锁便是通过这种方式获取锁的也就是为什么Java中任意对象可以作为锁的原因同时notify/notifyAll/wait等方法会使用到Monitor锁对象所以必须在同步代码块中使用。监视器Monitor有两种同步方式互斥与协作。 多线程环境下线程之间如果需要共享数据需要解决互斥访问数据的问题监视器Monitor可以确保监视器Monitor上的数据在同一时刻只会有一个线程在访问。 那么有个问题来了我们知道synchronized加锁加在对象上对象是如何记录锁状态的呢 答案是锁状态是被记录在每个对象的对象头Mark Word中下面我们一起认识一下对象的内存布局 对象的内存布局 HotSpot虚拟机中对象在内存中存储的布局可以分为三块区域对象头Header、实例数据Instance Data和对齐填充Padding。 对象头比如 hash码对象所属的年代对象锁锁状态标志偏向锁线程ID偏向时间数组长度数组对象等。Java对象头一般占有2个机器码在32位虚拟机中1个机器码等于4字节也就是32bit在64位虚拟机中1个机器码是8个字节也就是64bit但是 如果对象是数组类型则需要3个机器码因为JVM虚拟机可以通过Java对象的元数据信息确定Java对象的大小但是无法从数组的元数据来确认数组的大小所以用一块来记录数组长度。实例数据存放类的属性数据信息包括父类的属性信息对齐填充由于虚拟机要求 对象起始地址必须是8字节的整数倍。填充数据不是必须存在的仅仅是为了字节对齐对象头 HotSpot虚拟机的对象头包括两部分信息第一部分是“Mark Word”用于存储对象自身的运行时数据 如哈希码HashCode、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等它是实现轻量级锁和偏向锁的关键。这部分数据的长度在32位和64位的虚拟机暂 不考虑开启压缩指针的场景中分别为32个和64个Bits官方称它为“Mark Word”。对象需要存储的运行时数据很多其实已经超出了32、64位Bitmap结构所能记录的限度但是对象头信息是与对象自身定义的数据无关的额 外存储成本考虑到虚拟机的空间效率Mark Word被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息它会根据对象的状态复用自己的存储空间。例如在32位的HotSpot虚拟机 中对象未被锁定的状态下Mark Word的32个Bits空间中的25Bits用于存储对象哈希码HashCode4Bits用于存储对象分代年龄2Bits用于存储锁标志位1Bit固定为0在其他状态轻量级锁定、重量级锁定、GC标记、可偏向下对象的存储内容如下表所示。 但是如果对象是数组类型则需要三个机器码因为JVM虚拟机可以通过Java对象的元数据信息确定Java对象的大小但是无法从数组的元数据来确认数组的大小所以用一块来记录数组长度。 对象头信息是与对象自身定义的数据无关的额外存储成本但是考虑到虚拟机的空间效率Mark Word被设计成一个非固定的数据结构以便在极小的空间内存存储尽量多的数据它会根据对象的状态复用自己的存储空间也就是说Mark Word会随着程序的运行发生变化。 变化状态如下 32位虚拟机 锁状态 25bit 4bit 1bit 2bit 23bit 2bit 是否偏向锁是否禁用偏向 锁标志位 无锁态 对象的hashCode 分代年龄 0 01 轻量级锁 指向栈中锁记录的指针 00 重量级锁 指向Monitor的指针 10 GC标记 空 11 偏向锁 线程ID Epoch 分代年龄 1 01 64位虚拟机 现在我们虚拟机基本是64位的而64位的对象头有点浪费空间,JVM默认会开启指针压缩所以基本上也是按32位的形式记录对象头的。 手动设置-XX:UseCompressedOops 哪些信息会被压缩 1.对象的全局静态变量(即类属性) 2.对象头信息64位平台下原生对象头大小为16字节压缩后为12字节 3.对象的引用类型64位平台下引用类型本身大小为8字节压缩后为4字节 4.对象数组类型64位平台下数组类型本身大小为24字节压缩后16字节 在Scott oaks写的《java性能权威指南》第八章8.22节提到了当heap size堆内存大于32GB是用不了压缩指针的对象引用会额外占用20%左右的堆空间也就意味着要38GB的内存才相当于开启了指针压缩的32GB堆空间。 这是为什么呢看下面引用中的红字来自openjdk wikiCompressedOops - CompressedOops - OpenJDK Wiki。32bit最大寻址空间是4GB开启了压缩指针之后呢一个地址寻址不再是1byte而是8byte因为不管是32bit的机器还是64bit的机器java对象都是8byte对齐的而类是java中的基本单位对应的堆内存中都是一个一个的对象。 对象头分析工具 运行时对象头锁状态分析工具JOL他是OpenJDK开源工具包引入下方maven依赖 dependencygroupIdorg.openjdk.jol/groupIdartifactIdjol-core/artifactIdversion0.10/version /dependency 打印markword System.out.println(ClassLayout.parseInstance(object).toPrintable()); object为我们的锁对象 System.out.println()方法的坑 底层源码 得出结论多线程高并发环境下调用System.out.println()会成为同步阻塞调用性能极低不建议使用。 锁的膨胀升级过程【synchronized优化的思路】【重点】 锁的状态总共有四种无锁状态、偏向锁、轻量级锁和重量级锁。随着锁的竞争锁可以从偏向锁升级到轻量级锁再升级的重量级锁但是锁的升级是单向的也就是说只能从低到高升级不会出现锁的降级。从JDK 1.6 中默认是开启偏向锁和轻量级锁的可以通过-XX:-UseBiasedLocking来禁用偏向锁。下图为锁的升级全过程 偏向锁 偏向锁是Java 6之后加入的新锁它是一种针对加锁操作的优化手段经过研究发现在大多数情况下锁不仅不存在多线程竞争而且总是由同一线程多次获得因此为了减少同一线程获取锁(会涉及到一些CAS操作,耗时)的代价而引入偏向锁。偏向锁的核心思想是如果一个线程获得了锁那么锁就进入偏向模式此时Mark Word 的结构也变为偏向锁结构当这个线程再次请求锁时无需再做任何同步操作即获取锁的过程这样就省去了大量有关锁申请的操作从而也就提供程序的性能。所以对于没有锁竞争的场合偏向锁有很好的优化效果毕竟极有可能连续多次是同一个线程申请相同的锁。但是对于锁竞争比较激烈的场合偏向锁就失效了因为这样场合极有可能每次申请锁的线程都是不相同的因此这种场合下不应该使用偏向锁否则会得不偿失需要注意的是偏向锁失败后并不会立即膨胀为重量级锁而是先升级为轻量级锁。下面我们接着了解轻量级锁。 默认开启偏向锁开启偏向锁-XX:UseBiasedLocking -XX:BiasedLockingStartupDelay0关闭偏向锁-XX:-UseBiasedLocking 轻量级锁 倘若偏向锁失败虚拟机并不会立即升级为重量级锁它还会尝试使用一种称为轻量级锁的优化手段(1.6之后加入的)此时Mark Word 的结构也变为轻量级锁的结构。轻量级锁能够提升程序性能的依据是“对绝大部分的锁在整个同步周期内都不存在竞争”注意这是经验数据。需要了解的是轻量级锁所适应的场景是线程交替执行同步块的场合(线程自旋循环等待的时间较短的场景)如果存在同一时间访问同一锁的场合就会导致轻量级锁膨胀为重量级锁。 自旋 获取轻量级锁失败后虚拟机为了避免线程真实的在操作系统层面挂起还会进行一项称为自旋锁的优化手段。这种自旋锁的优化是基于在大多数情况下线程持有锁执行业务逻辑的时间都不会太长如果直接挂起阻塞操作系统层面的线程可能会得不偿失毕竟操作系统实现线程之间的切换时需要从用户态切换到内核态这个状态之间的转换需要相对比较长的时间时间成本相对较高。因此自旋锁会假设在不久将来当前的线程可以获得锁因此虚拟机会让当前想要获取锁的线程做几个空循环(这也是称为自旋的原因)一般不会太久可能是50个循环或100循环在经过若干次循环后如果得到锁就顺利进入临界区。如果还不能获得锁那就会将线程在操作系统层面挂起这就是自旋锁的优化方式这种方式确实也是可以提升效率的。最后没办法也就只能升级为重量级锁了。 锁消除 消除锁是虚拟机另外一种锁的优化这种优化更彻底Java虚拟机在JIT编译时(可以简单理解为当某段代码即将第一次被执行时进行编译又称即时编译)通过对运行上下文的扫描去除不可能存在共享资源竞争的锁通过这种方式消除没有必要的锁可以节省毫无意义的请求锁时间如下StringBuffer的append是一个同步方法但是在add方法中的StringBuffer属于一个局部变量并且不会被其他线程所使用因此StringBuffer不可能存在共享资源竞争的情景JVM会自动将其锁消除。锁消除的依据是逃逸分析的数据支持。 锁消除前提是java必须运行在server模式server模式会比client模式作更多的优化同时必须开启逃逸分析 :-XX:DoEscapeAnalysis 开启逃逸分析 -XX:EliminateLocks 表示开启锁消除。 锁粗化 举个例子来说明锁粗化 分析重量级锁和轻量级的总结为什么加重量级锁(挂起阻塞线程)时消耗性能大 轻量级锁 偏向锁失效后我们并没有直接升级为重量级锁而是变为轻量级锁。轻量级锁中未获取到锁的线程会进行自旋循环等待这个自旋循环等待的过程会消耗占用CPU的性能。但是假设线程竞争不激烈这个自旋循环等待的过程就很短那么消耗的CPU相对较低。但是如果线程竞争激烈时或业务逻辑执行时间较长导致单一线程获取到锁的概率降低自旋循环的次数超过额定范围那么就会由轻量级锁转化为重量级锁。 重量级锁 重量级锁就是把未获取到锁的线程进行阻塞挂起加入到一个EntryList队列中等待其它线程去唤醒。从操作系统底层内存空间模型来看Java程序是运行在用户空间的安全系数为ring3但是对于线程的调度我们必须切换到ring0级别的内核空间因为内核空间才具有调用线程的线程表【对于操作系统内部的程序指令才会一开始就运行在ring0安全系数较高。像第三方程序java程序一开始都运行在ring0级别的用户空间想要调用线程对应操作系统底层的库函数就必须要切换到ring0级别的内核空间切换的过程中我们会进行安全校验】。 所以当我们想唤醒一个阻塞的线程时需要从用户态切换回内核态(用户空间切换回内核空间)因为内核态中维护了线程表线程表中维护了与线程的一一映射的关系调度。CPU会去内核空间中的线程表进行调度线程地址映射最终由内核空间进行调度操作系统底层库函数进行调用JVM线程栈空间进行操作调用。 总结 我们知道从用户态切换到内核态所消耗的性能是非常大的。这就是为什么我们一直不舍得直接转化为重量级锁加重量级锁就好比直接把同步的任务交给操作系统底层了操作系统底层只能根据切换状态来维护是十分消耗性能的。但是如果线程竞争激烈未获取到锁的线程自旋循环等待所消耗的CPU性能已经大于加重量级锁时切换状态消耗的CPU性能时那么就需要从轻量级锁升级未重量级锁。 逃逸分析 代码 /*** Description: TODO* Author: etcEriksen* Date: 2023/3/4**/ public class TestScape {/*** 进行两种测试* 关闭逃逸分析同时调大堆空间避免堆内GC的发生如果有GC信息将会被打印出来* VM运行参数-Xmx4G -Xms4G -XX:-DoEscapeAnalysis -XX:PrintGCDetails -XX:HeapDumpOnOutOfMemoryError** 开启逃逸分析* VM运行参数-Xmx4G -Xms4G -XX:DoEscapeAnalysis -XX:PrintGCDetails -XX:HeapDumpOnOutOfMemoryError** 执行main方法后* jps 查看进程* jmap -histo 进程ID**/public static void main(String[] args) {long start System.currentTimeMillis();for (int i 0; i 500000; i) {alloc();}long end System.currentTimeMillis();//查看执行时间System.out.println(cost-time (end - start) ms);try {Thread.sleep(100000);} catch (InterruptedException e1) {e1.printStackTrace();}}private static S alloc() {//Jit对编译时会对代码进行 逃逸分析//并不是所有对象存放在堆区有的一部分存在线程栈空间//该创建的对象只在当前方法使用并不发生逃逸所以可以优化S student new S ();return student;}static class S {private long id;private int age;}}测试分析 方案1.关闭逃逸分析调大堆空间的内存大小(避免GC垃圾回收产生) 运行 通过命令行窗口查看发现在堆空间创建了50000个S实例对象 方案2.开启逃逸分析 设置JVM参数 运行 通过命令行窗口查看 原理分析 分离对象或标量替换。有的对象可能不需要作为一个连续的内存结构存在也可以被访问到那么对象的部分或全部可以不存储在堆内存而是分解为标量存储在栈空间中。这样就避免了在堆空间中重复创建多个S实例对象大大的节省了堆空间的内存 总结 使用逃逸分析编译器可以对代码做如下优化 一、同步省略。如果一个对象被发现只能从一个线程被访问到那么对于这个对象的操作可以不考虑同步。 二、将堆分配转化为栈分配。如果一个对象在子程序中被分配要使指向该对象的指针永远不会逃逸对象可能是栈分配的候选而不是堆分配。 三、分离对象或标量替换。有的对象可能不需要作为一个连续的内存结构存在也可以被访问到那么对象的部分或全部可以不存储在内存而是存储在CPU寄存器中。 是不是所有的对象和数组都会在堆内存分配空间 不一定 在Java代码运行时通过JVM参数可指定是否开启逃逸分析 -XX:DoEscapeAnalysis  表示开启逃逸分析 -XX:-DoEscapeAnalysis  表示关闭逃逸分析。从jdk 1.7开始已经默认开启逃逸分析如需关闭需要指定-XX:-DoEscapeAnalysis 但是逃逸分析存在缺点 1.技术不成熟 2.逃逸分析性能消耗较大 锁膨胀举例【了解即可】 前置知识须知 32位虚拟机(即使是64位也会进行指针压缩压缩为32位减少占用的空间) 下图从左往右高位到低位 锁状态 25bit最高位 4bit 1bit 2bit(最低位) 23bit 2bit 是否偏向锁是否禁用偏向 锁标志位 无锁态 对象的hashCode 分代年龄 0 01 轻量级锁 指向栈中锁记录的指针 00 重量级锁 指向Monitor的指针 10 GC标记 空 11 偏向锁 线程ID Epoch 分代年龄 1 01 打印输出的锁恰好和上图二进制位对应相反 举例1 为什么一上来没线程竞争就直接加轻量级锁 JVM启动的时候内部会启动大概几十个类并且会调用很多方法你不得不怀疑这些方法存在着同步的嫌疑所以得出一个结论JVM启动时内部会有多线程竞争激烈导致偏向锁可能直接升级为轻量级锁。 为了避免这种情况JVM搞出一个机制延迟加载偏向锁直接分配轻量级锁。这种做法是为了避免在JVM启动时由于线程竞争激烈导致锁升级所带来的性能消耗。 测试先休眠5秒再进行获取锁可能JVM延迟加载的休眠时间到了 结论 (1) 当调用偏向锁对象的hashCode时偏向锁升级为轻量级锁 因为偏向锁没有空间去存储哈希值。轻量级锁可以使用  (2) 轻量级锁的哈希值存储在lock record(markword)中 (3)重量级锁的哈希值记录在Monitor里面
http://www.dnsts.com.cn/news/248959.html

相关文章:

  • 树状结构的网站网站给他人做付刑事责任
  • 淄博哪有做网站的搜索引擎关键词竞价排名
  • 网站建设与管理管理课程手机如何做api网站
  • 常州建站优化相亲网与做网站
  • 网站建设系统分析包括哪些微官网怎么关注
  • 西安做网站公司云速app与网站用的服务器
  • 济南做网站设计巢湖网 网站
  • 网络服务器与网站建设社区团购小程序模板
  • 莆田做网站公司互联网架构师
  • 网站建设发货流程图建立个人网站主题
  • 不同代码做的网站后期维护情况外贸网站建设专业定制
  • 在设计赚钱的网站自己主机做标签电影网站
  • wordpress数据库里面改端口企业网站排名优化
  • 杭州专业网站制作设计国际消息新闻
  • 用网站建设费用建筑信息公开平台
  • 转播网站如何做目前最牛的二级分销模式
  • 江西省城乡住房建设厅培训网站福州 建站 软件
  • 成都市网站建做一个网站后期维护需要做什么
  • 化工类网站建设推广门户网站如何制作
  • 宿迁手机网站建设公司iis 配置 wordpress
  • 建设网站的目的和内容河北省工程建设信息网
  • 网站改版的方式免费建电子商务网站
  • 广东网站定制南京做网站dmooo
  • 东莞网站公司哪家好腾讯游戏推广代理加盟
  • WordPress让中文名图片显示小明seo教程
  • 用asp.net做后台网站wordpress主题资源网
  • 一个网站可以做多少个关键词wordpress提示没有
  • 做网站CentOS还是win好郑州网站建设公司有哪些
  • 网站设计建议云南省建设厅网站二级建造师
  • 网站建设佰金手指科杰十八七牛WordPress代码