synchronized
原理:
从JVM规范中可以看到Synchonized在JVM里的实现原理,JVM基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者的实现细节不一样。代码块同步是使用monitorenter 和monitorexit指令实现的,而方法同步是使用另外一种方式实现的,通过编译之后,同步方法与普通方法不同是被加入了一个acc_synchronized标识,然后jvm通过识别这个标识来确定这是一个同步方法。但是,方法的同步同样可以使用这两个指令来实现。 monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到结束位置和异常处,JVM要保证每个monitorenter必须有对应的monitorexit与之配对。任何对象都有一个monitor与之关联,线程执行到monitorenter 指令时,将会尝试获取对象所对应的monitor的所有权,即尝试获得对象的锁。
优化
在早期的时候,sync他是重量级的锁,就是操作系统层面的锁,需要从用户态切换到内核态。这是非常耗时的操作,性能低。
在java6之后,引入了一系列的优化,锁升级。随着的竞争加剧,锁会一步步升级。从低到高是:无锁,偏向锁,轻量级锁,重量级锁,并且是不可降级的。
对象的内存分布:
0 - 4 markword
4 - 8 markword
markword存储锁信息,gc信息
8 - 12 指向.class
以上统称为对象头。
后面是成员变量占的位置,不足8的整数倍,需要补字节到8的整数倍
重量级锁中指向互斥量的指针实际是指向monitor对象。
锁升级:
由低到高:无锁状态、偏向锁状态、轻量级锁状态(自旋锁)和重量级锁状态
偏向锁,轻量级锁,都是在用户态的。
用户态–》内核态 : 操作系统执行终端0x80
轻量级锁-------重量级锁:
jdk1.6之前:可以设置升级的线程自旋的次数阈值或者自旋的线程数阈值
jdk1.6之后:自适应,别设置了。
jvm启动时候的,有一段时间是不会启动偏向锁的,因为偏向锁适合的无线程竞争的情况,在明确知道会有多线程竞争的情况的时候,请直接使用轻量级锁,此时轻量级锁的效率可能更高,因为开始就启动偏向锁,还是会升级为轻量级锁,但是中间有一个偏向锁撤销的过程,浪费cpu资源。jvm启动必定是存在多线程竞争,所以jvm会延迟开启偏向锁。默认4s,也可以通过参数设置(-xx: BiasedLockingStartDelay== yourValue (unit:ms)
禁用偏向锁:xx - UseBiasedLocking
匿名偏向:
markword中的线程指针没有指向任何线程:匿名偏向。
如果synchronized(对象),对象中的markword中的偏向锁指针指向当前线程数,这个时候就不是匿名偏向锁了。
自旋锁
共享变量。
自旋锁缺点:
锁重入
一个方法可能被多个方法调用,而这个多个方法的同步逻辑不一样。
标签:同步,synchronized,对象,介绍,markword,线程,轻量级,偏向 From: https://blog.csdn.net/ZHOUJC5417/article/details/140893779