如何优化WordPress网站首页以获得更多流量?
摘要:网站首页seo关键词布局,wordpress+dux使用,定制网站开发是什么,十大骗子教育培训机构Synchronized与锁升级 一、概述 在多线程并发编程中 synchronized 一直是元老级角色,很多
网站首页seo关键词布局,wordpress+dux使用,定制网站开发是什么,十大骗子教育培训机构Synchronized与锁升级
一、概述
在多线程并发编程中 synchronized 一直是元老级角色#xff0c;很多人都会称呼它为重量级锁。但是#xff0c;随着 Java SE 1.6 对 synchronized 进行了各种优化之后#xff0c;有些情况下它就并不那么重了。 本文详细介绍 Java SE 1.6 中为…Synchronized与锁升级
一、概述
在多线程并发编程中 synchronized 一直是元老级角色很多人都会称呼它为重量级锁。但是随着 Java SE 1.6 对 synchronized 进行了各种优化之后有些情况下它就并不那么重了。 本文详细介绍 Java SE 1.6 中为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁以及锁的存储结构和升级过程。
二、实现同步的基础
Java 中的每个对象都可以作为锁具体变现为以下3中形式
对于普通同步方法锁是当前实例对象对于静态同步方法锁是当前类的 Class 对象对于同步方法块锁是 synchronized 括号里配置的对象
一个线程试图访问同步代码块时必须获取锁在退出或者抛出异常时必须释放锁。
三、实现方式
JVM 基于进入和退出 Monitor 对象来实现方法同步和代码块同步但是两者的实现细节不一样。
代码块同步通过使用 monitorenter 和 monitorexit 指令实现的同步方法ACC_SYNCHRONIZED 修饰
monitorenter 指令是在编译后插入到同步代码块的开始位置而 monitorexit 指令是在编译后插入到同步代码块的结束处或异常处对于同步方法个人觉得也是类似的原理进入方法前添加一个 monitorenter 指令退出方法后条件一个 monitorexit 指令。
为了证明 JVM 的实现方式下面通过反编译代码来证明
public class Demo {public void f1() {synchronized (Demo.class) {System.out.println(Hello World.);}}public synchronized void f2() {System.out.println(Hello World.);}}
编译之后的字节码如下(只摘取了方法的字节码):
public void f1();descriptor: ()Vflags: ACC_PUBLICCode:stack2, locals3, args_size10: ldc #2 // class me/snail/base/Demo2: dup3: astore_14: monitorenter5: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;8: ldc #4 // String Hello World.10: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V13: aload_114: monitorexit15: goto 2318: astore_219: aload_120: monitorexit21: aload_222: athrow23: returnException table:from to target type5 15 18 any18 21 18 anyLineNumberTable:line 6: 0line 7: 5line 8: 13line 9: 23StackMapTable: number_of_entries 2frame_type 255 /* full_frame */offset_delta 18locals [ class me/snail/base/Demo, class java/lang/Object ]stack [ class java/lang/Throwable ]frame_type 250 /* chop */offset_delta 4public synchronized void f2();descriptor: ()Vflags: ACC_PUBLIC, ACC_SYNCHRONIZEDCode:stack2, locals1, args_size10: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;3: ldc #4 // String Hello World.5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V8: returnLineNumberTable:line 12: 0line 13: 8
先说 f1() 方法发现其中一个 monitorenter 对应了两个 monitorexit这是不对的。但是仔细看 #15: goto 语句直接跳转到了 #23: return 处再看 #22: athrow 语句发现原来第二个 monitorexit 是保证同步代码块抛出异常时锁能得到正确的释放而存在的这就理解了。
综上发现同步代码块是通过 monitorenter 和 monitorexit 来实现的同步方法是加了一个 ACC_SYNCHRONIZED 修饰来实现的。
四、优化后synchronized锁的分类
级别从低到高依次是
无锁状态偏向锁状态轻量级锁状态重量级锁状态
锁可以升级但不能降级。即无锁 - 偏向锁 - 轻量级锁 - 重量级锁是单向的。
下面看一下每个锁状态时对象头中的 MarkWord 这一个字节中的内容是什么。
以32位系统为例
1、无锁状态
25bit4bit1bit(是否是偏向锁)2bit(锁标志位)对象的hashCode对象分代年龄001
这里的 hashCode 是 Object#hashCode 或者 System#identityHashCode 计算出来的值不是用户覆盖产生的 hashCode。 2、偏向锁状态
偏向锁单线程竞争当线程A第一次竞争到锁时通过修改MarkWord中的偏向线程ID、偏向模式。如果不存在其他线程竞争那么持有偏向锁的线程将永远不需要进行同步。 主要作用 ● 当一段同步代码一直被同一个线程多次访问由于只有一个线程那么该线程在后续访问时便会自动获得锁 ● 同一个老顾客来访直接老规矩行方便 结论 ● HotSpot的作者经过研究发现大多数情况下在多线程情况下锁不仅不存在多线程竞争还存在由同一个线程多次获得的情况偏向锁就是在这种情况下出现的它的出现是为了解决只有一个线程执行同步时提高性能。 ● 偏向锁会偏向于第一个访问锁的线程如果在接下来的运行过程中该锁没有被其他线程访问则持有偏向锁的线程将永远不需要出发同步。也即偏向锁在资源在没有竞争情况下消除了同步语句懒得连CAS操作都不做了直接提高程序性能。
理论落地 技术实现 偏向锁JVM命令 偏向锁的撤销 ● 当有另外一个线程逐步来竞争锁的时候就不能再使用偏向锁了要升级为轻量级锁使用的是等到竞争出现才释放锁的机制 ● 竞争线程尝试CAS更新对象头失败会等到全局安全点此时不会执行任何代码撤销偏向锁同时检查持有偏向锁的线程是否还在执行 ○ 第一个线程正在执行Synchronized方法处于同步块它还没有执行完其他线程来抢夺该偏向锁会被取消掉并出现锁升级此时轻量级锁由原来持有偏向锁的线程持有继续执行同步代码块而正在竞争的线程会自动进入自旋等待获得该轻量级锁 ○ 第一个线程执行完Synchronized退出同步块则将对象头设置为无所状态并撤销偏向锁重新偏向。 Java15以后逐步废弃偏向锁需要手动开启-------维护成本高
3、轻锁
概念多线程竞争但是任意时候最多只有一个线程竞争即不存在锁竞争太激烈的情况也就没有线程阻塞。
主要作用有线程来参与锁的竞争但是获取锁的冲突时间极短----------本质是自旋锁CAS 轻量锁的获取 自旋一定程度和次数Java8 之后是自适应自旋锁------意味着自旋的次数不是固定不变的
线程如果自旋成功了那下次自旋的最大次数会增加因为JVM认为既然上次成功了那么这一次也大概率会成功如果很少会自选成功那么下次会减少自旋的次数甚至不自旋避免CPU空转
轻量锁和偏向锁的区别
争夺轻量锁失败时自旋尝试抢占锁轻量级锁每次退出同步块都需要释放锁而偏向锁是在竞争发生时才释放锁
4、重量级锁状态
有大量线程参与锁的竞争冲突性很高 五.小总结
锁升级的过程 锁升级后hashcode去哪儿了? ● 各种锁优缺点、synchronized锁升级和实现原理
